func main() { // Bind a new logger to a variable. You may create any number of loggers. ctx := kiwi.New() // For starting write ctx records to some writer output should be initialized. out := kiwi.SinkTo(os.Stdout, kiwi.UseLogfmt()).Start() // setup context of the logger ctx.With("userID", 1000, "host", "local", "startedAt", time.Now()) // This record will be supplemented by startedAt value of time.Now().String() ctx.Add("sample", 1).Log() // This record also will be supplemented by the same value of the time. // Because context value evalueted when it was added by ctx.With(). ctx.Add("sample", 2).Log() // You can provide deferred evaluation of context or ctx values if you add them wrapped // with func() interface{}, where interface should be one of scalar golang types. ctx.With("currentTime", func() string { return time.Now().String() }) // Get previously saved context for use in the application. // They were keep as is without conversion to strings. currentContext := ctx.GetContext() fmt.Printf("some of the context values are: %d, %s\n", currentContext["userID"], currentContext["host"]) // These records will be output each its own currentTime value because currentTime will // be evaluated on each Log() call. ctx.Add("sample", 3).Log() ctx.Add("sample", 4).Log() out.Flush() }
func BenchmarkLevelsKiwiTypedHelpers_JSON(b *testing.B) { buf := &bytes.Buffer{} b.ResetTimer() l := kiwi.New() l.With("_n", "bench", "_p", pid) l.WithTimestamp(time.RFC3339) kiwi.LevelName = "l" out := kiwi.SinkTo(buf, kiwi.UseJSON()).Start() for i := 0; i < b.N; i++ { l.AddPairs( kiwi.AsInt("key", 1), kiwi.AsFloat64("key2", 3.141592), kiwi.AsString("key3", "string"), kiwi.AsBool("key4", false)).Debug() l.AddPairs( kiwi.AsInt("key", 1), kiwi.AsFloat64("key2", 3.141592), kiwi.AsString("key3", "string"), kiwi.AsBool("key4", false)).Info() l.AddPairs( kiwi.AsInt("key", 1), kiwi.AsFloat64("key2", 3.141592), kiwi.AsString("key3", "string"), kiwi.AsBool("key4", false)).Warn() l.AddPairs( kiwi.AsInt("key", 1), kiwi.AsFloat64("key2", 3.141592), kiwi.AsString("key3", "string"), kiwi.AsBool("key4", false)).Error() } b.StopTimer() out.Close() }
func main() { // Bind a new logger to a variable. You may create any number of loggers. log := kiwi.New() tmpFile, _ := os.Create("/tmp/something-completely-different.log") // You can set arbitrary number of outputs. // But they will remain unused until you explicitly start them with Start(). info := kiwi.SinkTo(os.Stdout, kiwi.UseLogfmt()) errors := kiwi.SinkTo(os.Stderr, kiwi.UseLogfmt()) something := kiwi.SinkTo(tmpFile, kiwi.UseLogfmt()) // Each record by default will copied to all outputs. // But until you Start() any output the records will just dropped as the sample record below. log.Add("just something that will lost") // Each output allows filter out any records and write any other. // You specify filter for the keys (key filter). // Each of these keys should be presented in the record. errors.WithKey("error", "msg") // The filter may take into account key values. So only records with levels // ERROR and FATAL will be passed filter and written to stderr. errors.WithValue("level", "ERROR", "FATAL").Start() // Vice versa you can filter out some keys. info.WithoutKey("error") // And define another set of key-val pairs for distinguish outputs. info.WithValue("level", "INFO", "WARNING").Start() // It will output all records from outputs above if they have key "something". // So you can duplicate some records to several log files based on some criteria. something.WithKey("something").Start() // So if you not define any clauses (WithKey/WithoutKey/WithValue/WithoutValues) // then all records will copied to an output. // Let's go! log.Add("level", "INFO", "sample-record", 1, "key", "value") log.Add("level", "INFO", "sample-record", 2, "something").Log() log.Add("level", "ERROR", "msg", "Error description.").Log() log.Add("level", "FATAL").Log() // Until you call Log() records not copied to outputs. log.Log() }
// Test logging of float value in default (scientific) format. func TestGlobalLogger_LogFloatValue_Logfmt(t *testing.T) { output := bytes.NewBufferString("") out := kiwi.SinkTo(output, kiwi.UseLogfmt()).Start() kiwi.Log("k", 3.14159265359) out.Flush().Close() if strings.TrimSpace(output.String()) != "k=3.14159265359e+00" { println(output.String()) t.Fail() } }
// Test logging of negative integer value. func TestGlobalLogger_LogNegativeIntValue_Logfmt(t *testing.T) { output := bytes.NewBufferString("") out := kiwi.SinkTo(output, kiwi.UseLogfmt()).Start() kiwi.Log("k", 123) out.Flush().Close() if strings.TrimSpace(output.String()) != "k=123" { println(output.String()) t.Fail() } }
// Test logging of byte array. func TestGlobalLogger_LogBytesValue_Logfmt(t *testing.T) { output := bytes.NewBufferString("") out := kiwi.SinkTo(output, kiwi.UseLogfmt()).Start() kiwi.Log("k", []byte("The sample string with a lot of spaces.")) out.Flush().Close() if strings.TrimSpace(output.String()) != "k=\"The sample string with a lot of spaces.\"" { println(output.String()) t.Fail() } }
// Test logging of the numeric key. func TestGlobalLogger_LogNumericKey_Logfmt(t *testing.T) { output := bytes.NewBufferString("") out := kiwi.SinkTo(output, kiwi.UseLogfmt()).Start() kiwi.Log(123, "The sample value.") out.Flush().Close() if strings.TrimSpace(output.String()) != "123=\"The sample value.\"" { println(output.String()) t.Fail() } }
// Test logging of the key with spaces. func TestGlobalLogger_LogKeyWithSpaces_Logfmt(t *testing.T) { output := bytes.NewBufferString("") out := kiwi.SinkTo(output, kiwi.UseLogfmt()).Start() kiwi.Log("key with spaces", "The sample value.") out.Flush().Close() if strings.TrimSpace(output.String()) != "\"key with spaces\"=\"The sample value.\"" { println(output.String()) t.Fail() } }
// Test logging of complex number. func TestGlobalLogger_LogComplexValue_Logfmt(t *testing.T) { output := bytes.NewBufferString("") out := kiwi.SinkTo(output, kiwi.UseLogfmt()).Start() kiwi.Log("k", .12345E+5i, "k2", 1.e+0i) out.Flush().Close() if strings.TrimSpace(output.String()) != "k=(0.000000+12345.000000i) k2=(0.000000+1.000000i)" { println(output.String()) t.Fail() } }
// Test logging of boolean value. func TestGlobalLogger_LogBoolValue_Logfmt(t *testing.T) { output := bytes.NewBufferString("") out := kiwi.SinkTo(output, kiwi.UseLogfmt()).Start() kiwi.Log("k", true, "k2", false) out.Flush().Close() if strings.TrimSpace(output.String()) != "k=true k2=false" { println(output.String()) t.Fail() } }
func BenchmarkLevelsKiwiGlobal_JSON(b *testing.B) { buf := &bytes.Buffer{} b.ResetTimer() out := kiwi.SinkTo(buf, kiwi.UseJSON()).Start() for i := 0; i < b.N; i++ { kiwi.Log("t", time.Now().Format(time.RFC3339), "l", "debug", "_n", "bench", "_p", pid, "key", 1, "key2", 3.141592, "key3", "string", "key4", false) kiwi.Log("t", time.Now().Format(time.RFC3339), "l", "info", "_n", "bench", "_p", pid, "key", 1, "key2", 3.141592, "key3", "string", "key4", false) kiwi.Log("t", time.Now().Format(time.RFC3339), "l", "warn", "_n", "bench", "_p", pid, "key", 1, "key2", 3.141592, "key3", "string", "key4", false) kiwi.Log("t", time.Now().Format(time.RFC3339), "l", "error", "_n", "bench", "_p", pid, "key", 1, "key2", 3.141592, "key3", "string", "key4", false) } b.StopTimer() out.Close() }
// Test logging of time literal. func TestGlobalLogger_LogTimeValue_Logfmt(t *testing.T) { output := bytes.NewBufferString("") out := kiwi.SinkTo(output, kiwi.UseLogfmt()).Start() value := time.Now() valueString := value.Format(kiwi.TimeLayout) kiwi.Log("k", value) out.Flush().Close() if strings.TrimSpace(output.String()) != fmt.Sprintf("k=%s", valueString) { println(output.String()) t.Fail() } }
// Test logging of float value in fixed format. func TestGlobalLogger_LogFixedFloatValue_Logfmt(t *testing.T) { output := bytes.NewBufferString("") out := kiwi.SinkTo(output, kiwi.UseLogfmt()).Start() kiwi.FloatFormat = 'f' kiwi.Log("k", 3.14159265359) out.Flush().Close() if strings.TrimSpace(output.String()) != "k=3.14159265359" { println(output.String()) t.Fail() } // Turn back to default format. kiwi.FloatFormat = 'e' }
func BenchmarkLevelsKiwiTypedHelpersComplex_JSON(b *testing.B) { buf := &bytes.Buffer{} b.ResetTimer() l := kiwi.New() l.With("_n", "bench", "_p", pid) l.WithTimestamp(time.RFC3339) kiwi.LevelName = "l" out := kiwi.SinkTo(buf, kiwi.UseJSON()).Start() for i := 0; i < b.N; i++ { l.AddPairs(kiwi.AsInt("key", 1), kiwi.AsStringer("obj", testObject)).Debug() l.AddPairs(kiwi.AsInt("key", 1), kiwi.AsStringer("obj", testObject)).Info() l.AddPairs(kiwi.AsInt("key", 1), kiwi.AsStringer("obj", testObject)).Warn() l.AddPairs(kiwi.AsInt("key", 1), kiwi.AsStringer("obj", testObject)).Error() } b.StopTimer() out.Close() }
func BenchmarkLevelsKiwi_JSON(b *testing.B) { buf := &bytes.Buffer{} b.ResetTimer() l := kiwi.New() l.With("_n", "bench", "_p", pid) l.WithTimestamp(time.RFC3339) kiwi.LevelName = "l" out := kiwi.SinkTo(buf, kiwi.UseJSON()).Start() for i := 0; i < b.N; i++ { l.Debug("key", 1, "key2", 3.141592, "key3", "string", "key4", false) l.Info("key", 1, "key2", 3.141592, "key3", "string", "key4", false) l.Warn("key", 1, "key2", 3.141592, "key3", "string", "key4", false) l.Error("key", 1, "key2", 3.141592, "key3", "string", "key4", false) } b.StopTimer() out.Close() }
func BenchmarkLevelsKiwiComplex_JSON(b *testing.B) { buf := &bytes.Buffer{} b.ResetTimer() l := kiwi.New() l.With("_n", "bench", "_p", pid) l.WithTimestamp(time.RFC3339) kiwi.LevelName = "l" out := kiwi.SinkTo(buf, kiwi.UseJSON()).Start() for i := 0; i < b.N; i++ { l.Debug("key", 1, "obj", testObject) l.Info("key", 1, "obj", testObject) l.Warn("key", 1, "obj", testObject) l.Error("key", 1, "obj", testObject) } b.StopTimer() out.Close() }
func main() { // Bind a new logger to a variable. You may create any number of loggers. log := kiwi.New() // For starting write log records to some writer output should be initialized. output := kiwi.SinkTo(os.Stdout, kiwi.UseLogfmt()).Start() log.Add("sample-record", 1, "key", "value") log.Log() // Most logger and output operations support chaining. log.Add("sample-record", 2, "key", "value", "key2", 123).Log() // On pause output will drop any incoming records. output.Stop() log.Add("this record will be dropped because single output we declared is on pause") output.Start() // You can explicitly remove output but it will automatically closed on application exit. output.Close() }
func main() { kiwi.SinkTo(os.Stdout, kiwi.UseLogfmt()).Start() l := kiwi.New() l.Add("sample-record", 1).Log() }