{"id":13830278,"url":"https://github.com/icefed/zlog","last_synced_at":"2026-01-17T11:26:35.332Z","repository":{"id":193315547,"uuid":"688569743","full_name":"icefed/zlog","owner":"icefed","description":"A JSON structured logger implementation, compatible with golang slog ","archived":false,"fork":false,"pushed_at":"2025-11-15T06:39:18.000Z","size":236,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-15T08:16:50.218Z","etag":null,"topics":["go","golang","log","logger","logging","slog","zap"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/icefed.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-09-07T16:11:57.000Z","updated_at":"2025-10-03T02:45:37.000Z","dependencies_parsed_at":"2025-10-06T08:20:24.357Z","dependency_job_id":null,"html_url":"https://github.com/icefed/zlog","commit_stats":null,"previous_names":["icefed/zlog"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/icefed/zlog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icefed%2Fzlog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icefed%2Fzlog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icefed%2Fzlog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icefed%2Fzlog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/icefed","download_url":"https://codeload.github.com/icefed/zlog/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icefed%2Fzlog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28507398,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T10:25:30.148Z","status":"ssl_error","status_checked_at":"2026-01-17T10:25:29.718Z","response_time":85,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","log","logger","logging","slog","zap"],"created_at":"2024-08-04T10:00:58.167Z","updated_at":"2026-01-17T11:26:35.321Z","avatar_url":"https://github.com/icefed.png","language":"Go","funding_links":[],"categories":["Formatting"],"sub_categories":[],"readme":"# zlog - JSON structured handler/logger for Golang slog\n\n[![GitHub Tag](https://img.shields.io/github/v/tag/icefed/zlog)](https://github.com/icefed/zlog/tags)\n[![Go Reference](https://pkg.go.dev/badge/github.com/icefed/zlog.svg)](https://pkg.go.dev/github.com/icefed/zlog)\n[![Go Report Card](https://goreportcard.com/badge/github.com/icefed/zlog)](https://goreportcard.com/report/github.com/icefed/zlog)\n![Build Status](https://github.com/icefed/zlog/actions/workflows/test.yml/badge.svg)\n[![Coverage](https://img.shields.io/codecov/c/github/icefed/zlog)](https://codecov.io/gh/icefed/zlog)\n[![License](https://img.shields.io/github/license/icefed/zlog)](./LICENSE)\n\n## Features\n- JSON Structured logging\n- Logger with format method(printf-style)\n- Development mode with human-friendly output\n- WithCallerSkip to skip caller\n- Context extractor for Record context\n- Custom time formatter for buildin attribute time value\n- Custom logging level, ex: add a new level \"trace\"\n\n## Usage\n\nMore examples can be found in [examples](https://github.com/icefed/zlog/tree/master/examples).\n\nBecause zlog implements the slog.Handler interface, you can create a zlog.JSONHander and use slog.Logger.\n```go\nimport (\n    \"context\"\n    \"log/slog\"\n\n    \"github.com/icefed/zlog\"\n)\n\nfunc main() {\n    h := zlog.NewJSONHandler(\u0026zlog.Config{\n\t\tHandlerOptions: slog.HandlerOptions{\n\t\t\tLevel: slog.LevelDebug,\n\t\t},\n    })\n    log := slog.New(h)\n\n    log.Info(\"hello world\")\n    // ...\n    log.With(slog.String(\"app\", \"test\")).\n        Error(\"db execution failed\", \"error\", err)\n    log.LogAttrs(context.Background(), slog.LevelInfo, \"this is a info message\", slog.String(\"app\", \"test\"))\n}\n```\n\nOr you can use zlog.Logger, which implements all slog.Logger methods and is compatible.\nThen you can use Infof and other methods that support format format.\n```go\nimport (\n\t\"context\"\n\t\"log/slog\"\n\n\t\"github.com/icefed/zlog\"\n)\n\nfunc main() {\n\th := zlog.NewJSONHandler(\u0026zlog.Config{\n\t\tHandlerOptions: slog.HandlerOptions{\n\t\t\tLevel: slog.LevelDebug,\n\t\t},\n\t})\n\tlog := zlog.New(h)\n\tlog.Info(\"hello world\")\n\n\tlog.Log(context.Background(), slog.LevelInfo, \"this is a info message\")\n\t// ...\n\tlog.Debugf(\"get value %s from map by key %s\", v, k)\n}\n```\n\n### Development mode\n\nDevelopment mode, like zap development, outputs buildin attributes in Text format for better readability.  If development mode is enabled and writer is a terminal, the level field will be printed in color.\n```go\npackage main\n\nimport (\n\t\"log/slog\"\n\n\t\"github.com/icefed/zlog\"\n)\n\nfunc main() {\n\t// start development mode with Config\n\th := zlog.NewJSONHandler(\u0026zlog.Config{\n\t\tHandlerOptions: slog.HandlerOptions{\n\t\t\tLevel: slog.LevelDebug,\n\t\t},\n\t\tDevelopment: true,\n\t})\n\n\t// turn on development mode with WithOptions\n\th = h.WithOptions(zlog.WithDevelopment(true))\n\tlog := zlog.New(h)\n\n\tlog.Debug(\"Processing data file\", \"file\", \"data.json\")\n\tlog.Info(\"Application started successfully\",\n\t\tslog.String(\"version\", \"1.0.0\"),\n\t\tslog.String(\"environment\", \"dev\"))\n\tlog.Warn(\"Deprecated method 'foo()' is being used\", slog.Int(\"warning_code\", 123))\n\tlog.Error(\"Failed to connect to the database\", \"error_code\", 500, \"component\", \"DatabaseConnection\")\n}\n```\n\nOutputs:\n![](images/development.png)\n\n### Enable stack trace\n\nSet StacktraceEnabled to true to enable printing log stack trace, the default print slog.LevelError above the level,\n```go\nh := zlog.NewJSONHandler(\u0026zlog.Config{\n    HandlerOptions: slog.HandlerOptions{\n        Level: slog.LevelDebug,\n    },\n    StacktraceEnabled: true,\n})\n\n// set custom stacktrace key\nh = h.WithOptions(zlog.WithStacktraceKey(\"stack\"))\n```\n\n### Custom time formatter\n\nBy default, when printing logs, the time field is formatted with `RFC3339Milli`(`2006-01-02T15:04:05.999Z07:00`). If you want to modify the format, you can configure TimeFormatter in Config.\n```go\nh := zlog.NewJSONHandler(\u0026zlog.Config{\n    HandlerOptions: slog.HandlerOptions{\n        Level: slog.LevelDebug,\n    },\n    TimeFormatter: func(buf []byte,t time.Time) []byte {\n        return t.AppendFormat(buf, time.RFC3339Nano)\n    },\n})\n\nlog := zlog.New(h)\nlog.Info(\"this is a log message with RFC3339Nano format\")\n\n// use int timestamp format with microsecond precision\nlog = log.WithOptions(zlog.WithTimeFormatter(func(buf []byte, t time.Time) []byte {\n    return strconv.AppendInt(buf, t.UnixMicro(), 10)\n}))\nlog.Info(\"this is a log message in int timestamp format\")\n```\n\nOutputs:\n```\n{\"time\":\"2023-09-09T19:02:28.704746+08:00\",\"level\":\"INFO\",\"msg\":\"this is a log message with RFC3339Nano format\"}\n{\"time\":\"1694257348705059\",\"level\":\"INFO\",\"msg\":\"this is a log message with int timestamp format\"}\n```\n\n### Context extractor\n\nWe often need to extract the value from the context and print it to the log, for example, an apiserver receives a user request and prints trace and user information to the log.\n\nThis example shows how to use the context, and print OpenTelemetry trace in log. If you have an api server that supports OpenTelemetry, you can use this example in your handler middleware and print trace in each log.\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"log/slog\"\n\n\t\"go.opentelemetry.io/otel\"\n\tsdktrace \"go.opentelemetry.io/otel/sdk/trace\"\n\t\"go.opentelemetry.io/otel/sdk/trace/tracetest\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/icefed/zlog\"\n)\n\n// traceContextExtractor implement the ContextExtractor, extracts trace context from context\nfunc traceContextExtractor(ctx context.Context) []slog.Attr {\n\tspanContext := trace.SpanContextFromContext(ctx)\n\tif spanContext.IsValid() {\n\t\treturn []slog.Attr{\n\t\t\tslog.Group(\"trace\",\n\t\t\t\tslog.String(\"traceID\", spanContext.TraceID().String()),\n\t\t\t\tslog.String(\"spanID\", spanContext.SpanID().String()),\n\t\t\t),\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc parentFun(ctx context.Context, tracer trace.Tracer) {\n\tctx, parentSpan := tracer.Start(ctx, \"caller1\")\n\tdefer parentSpan.End()\n\n\t// print log\n\tslog.InfoContext(ctx, \"call parentFun\")\n\n\tchildFun(ctx, tracer)\n}\n\nfunc childFun(ctx context.Context, tracer trace.Tracer) {\n\tctx, childSpan := tracer.Start(ctx, \"caller2\")\n\tdefer childSpan.End()\n\n\t// print log\n\tslog.InfoContext(ctx, \"call childFun\")\n}\n\nfunc main() {\n\t// create a logger with traceContextExtractor\n\th := zlog.NewJSONHandler(nil)\n\th = h.WithOptions(zlog.WithContextExtractor(traceContextExtractor))\n\tlog := slog.New(h)\n\tslog.SetDefault(log)\n\n\t// prepare a call with trace context\n\texporter := tracetest.NewInMemoryExporter()\n\ttracerProvider := sdktrace.NewTracerProvider(\n\t\tsdktrace.WithBatcher(exporter),\n\t)\n\totel.SetTracerProvider(tracerProvider)\n\ttracer := otel.Tracer(\"api\")\n\tctx := context.Background()\n\tparentFun(ctx, tracer)\n}\n```\n\nOutputs:\n```\n{\"time\":\"2023-09-08T20:12:14.733\",\"level\":\"INFO\",\"msg\":\"call parentFun\",\"trace\":{\"traceID\":\"95f0717d9da16177176efdbc7c06bfbd\",\"spanID\":\"7718edf7b2a8388d\"}}\n{\"time\":\"2023-09-08T20:12:14.733\",\"level\":\"INFO\",\"msg\":\"call childFun\",\"trace\":{\"traceID\":\"95f0717d9da16177176efdbc7c06bfbd\",\"spanID\":\"ef83f673951742b0\"}}\n```\n\n### Custom logging level\n\nslog defines four logging levels, Debug, Info, Warn and Error, but it's not easy to add a new level.\nzlog provides a solution for this, you can use the LevelStringer to define your own logging level.\n\nThe following example shows how to use the LevelStringer to define a new logging level called `LevelTrace`.\n\n```go\nfunc main() {\n\th := zlog.NewJSONHandler(\u0026zlog.Config{\n\t\tHandlerOptions: slog.HandlerOptions{\n\t\t\tLevel: LevelTrace,\n\t\t},\n\t\tLevelStringer: customLevelStringer,\n\t})\n\tlog := slog.New(h)\n\tlog.Log(context.Background(), LevelTrace, \"hello world\")\n\tlog.Debug(\"hello world\")\n\tlog.Info(\"hello world\")\n\tlog.Warn(\"hello world\")\n\tlog.Error(\"hello world\")\n}\n\n// LevelTrace define a Trace level\nvar LevelTrace = slog.LevelDebug - 4\n\nfunc customLevelStringer(l slog.Level) string {\n\tstr := func(base string, val slog.Level) string {\n\t\tif val == 0 {\n\t\t\treturn base\n\t\t}\n\t\tb := strings.Builder{}\n\t\tb.WriteString(base)\n\t\tif val \u003e 0 {\n\t\t\tb.WriteString(\"+\")\n\t\t}\n\t\tb.WriteString(strconv.Itoa(int(val)))\n\t\treturn b.String()\n\t}\n\n\tswitch {\n\tcase l \u003c slog.LevelDebug:\n\t\treturn str(\"TRACE\", l-LevelTrace)\n\tcase l \u003c slog.LevelInfo:\n\t\treturn str(\"DEBUG\", l-slog.LevelDebug)\n\tcase l \u003c slog.LevelWarn:\n\t\treturn str(\"INFO\", l-slog.LevelInfo)\n\tcase l \u003c slog.LevelError:\n\t\treturn str(\"WARN\", l-slog.LevelWarn)\n\tdefault:\n\t\treturn str(\"ERROR\", l-slog.LevelError)\n\t}\n}\n```\n\nOutputs:\n```\n{\"time\":\"2025-11-17T20:13:56.293+08:00\",\"level\":\"TRACE\",\"msg\":\"hello world\"}\n{\"time\":\"2025-11-17T20:13:56.294+08:00\",\"level\":\"DEBUG\",\"msg\":\"hello world\"}\n{\"time\":\"2025-11-17T20:13:56.294+08:00\",\"level\":\"INFO\",\"msg\":\"hello world\"}\n{\"time\":\"2025-11-17T20:13:56.294+08:00\",\"level\":\"WARN\",\"msg\":\"hello world\"}\n{\"time\":\"2025-11-17T20:13:56.294+08:00\",\"level\":\"ERROR\",\"msg\":\"hello world\"}\n```\n\n## Benchmarks\n\nTest modified from [zap benchmarking suite](https://github.com/uber-go/zap/tree/master/benchmarks).\n\n```bench\ngoos: darwin\ngoarch: arm64\npkg: github.com/icefed/zlog/benchmarks\nBenchmarkDisabledWithoutFields/slog-10          1000000000               0.6019 ns/op          0 B/op          0 allocs/op\nBenchmarkDisabledWithoutFields/slog_with_zlog-10                1000000000               0.5913 ns/op          0 B/op          0 allocs/op\nBenchmarkDisabledWithoutFields/zlog-10                          1000000000               0.5496 ns/op          0 B/op          0 allocs/op\nBenchmarkDisabledWithoutFields/slog_with_zap-10                 1000000000               0.8184 ns/op          0 B/op          0 allocs/op\nBenchmarkDisabledWithoutFields/zap-10                           1000000000               0.6048 ns/op          0 B/op          0 allocs/op\nBenchmarkDisabledWithoutFields/zerolog-10                       1000000000               0.3016 ns/op          0 B/op          0 allocs/op\nBenchmarkDisabledAddingFields/slog-10                           57371786               208.7 ns/op           576 B/op          6 allocs/op\nBenchmarkDisabledAddingFields/slog_with_zlog-10                 56256844               208.3 ns/op           576 B/op          6 allocs/op\nBenchmarkDisabledAddingFields/zlog-10                           58574133               205.8 ns/op           576 B/op          6 allocs/op\nBenchmarkDisabledAddingFields/slog_with_zap-10                  58468917               206.9 ns/op           576 B/op          6 allocs/op\nBenchmarkDisabledAddingFields/zap-10                            41587197               295.7 ns/op           864 B/op          6 allocs/op\nBenchmarkDisabledAddingFields/zerolog-10                        303398799               39.08 ns/op           88 B/op          2 allocs/op\nBenchmarkWithoutFields/slog-10                                  47158194               231.9 ns/op             0 B/op          0 allocs/op\nBenchmarkWithoutFields/slog_with_zlog-10                        143867673               81.77 ns/op            0 B/op          0 allocs/op\nBenchmarkWithoutFields/zlog-10                                  182174908               64.98 ns/op            0 B/op          0 allocs/op\nBenchmarkWithoutFields/slog_with_zap-10                         125818678               95.04 ns/op            0 B/op          0 allocs/op\nBenchmarkWithoutFields/zap-10                                   169056685               72.34 ns/op            0 B/op          0 allocs/op\nBenchmarkWithoutFields/zerolog-10                               348895234               35.03 ns/op            0 B/op          0 allocs/op\nBenchmarkAccumulatedContext/slog-10                             51551946               241.8 ns/op             0 B/op          0 allocs/op\nBenchmarkAccumulatedContext/slog_with_zlog-10                   138282912               90.81 ns/op            0 B/op          0 allocs/op\nBenchmarkAccumulatedContext/zlog-10                             184607311               66.28 ns/op            0 B/op          0 allocs/op\nBenchmarkAccumulatedContext/slog_with_zap-10                    132471319               89.32 ns/op            0 B/op          0 allocs/op\nBenchmarkAccumulatedContext/zap-10                              167639162               76.73 ns/op            0 B/op          0 allocs/op\nBenchmarkAccumulatedContext/zerolog-10                          314418170               36.53 ns/op            0 B/op          0 allocs/op\nBenchmarkAddingFields/slog-10                                    4498432              2639 ns/op            3951 B/op         38 allocs/op\nBenchmarkAddingFields/slog_with_zlog-10                          9287110              1300 ns/op            1344 B/op         20 allocs/op\nBenchmarkAddingFields/zlog-10                                    9383146              1290 ns/op            1344 B/op         20 allocs/op\nBenchmarkAddingFields/slog_with_zap-10                           6758552              1776 ns/op            2218 B/op         23 allocs/op\nBenchmarkAddingFields/zap-10                                     8615821              1389 ns/op            1508 B/op         18 allocs/op\nBenchmarkAddingFields/zerolog-10                                 9067814              1309 ns/op            2031 B/op         15 allocs/op\nBenchmarkKVArgs/slog-10                                          4663335              2562 ns/op            3586 B/op         40 allocs/op\nBenchmarkKVArgs/slog_with_zlog-10                                9989289              1186 ns/op             978 B/op         22 allocs/op\nBenchmarkKVArgs/zlog-10                                         10343742              1171 ns/op             978 B/op         22 allocs/op\nBenchmarkKVArgs/slog_with_zap-10                                 7146567              1661 ns/op            1851 B/op         25 allocs/op\nBenchmarkKVArgs/zap-10                                           6913246              1730 ns/op            2352 B/op         24 allocs/op\nBenchmarkKVArgs/zerolog-10                                       4937739              2431 ns/op            3355 B/op         40 allocs/op\nPASS\nok      github.com/icefed/zlog/benchmarks       471.856s\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficefed%2Fzlog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ficefed%2Fzlog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficefed%2Fzlog/lists"}