{"id":38860577,"url":"https://github.com/j-keck/plog","last_synced_at":"2026-01-17T14:21:37.475Z","repository":{"id":57480819,"uuid":"181441393","full_name":"j-keck/plog","owner":"j-keck","description":"golang logging library","archived":false,"fork":false,"pushed_at":"2020-02-19T08:36:03.000Z","size":40,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-13T17:00:44.713Z","etag":null,"topics":["go","logging","logging-library"],"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/j-keck.png","metadata":{"files":{"readme":"README.org","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}},"created_at":"2019-04-15T08:09:06.000Z","updated_at":"2020-02-19T08:35:59.000Z","dependencies_parsed_at":"2022-09-26T17:41:22.675Z","dependency_job_id":null,"html_url":"https://github.com/j-keck/plog","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/j-keck/plog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j-keck%2Fplog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j-keck%2Fplog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j-keck%2Fplog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j-keck%2Fplog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/j-keck","download_url":"https://codeload.github.com/j-keck/plog/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j-keck%2Fplog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28509945,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T13:38:16.342Z","status":"ssl_error","status_checked_at":"2026-01-17T13:37:44.060Z","response_time":85,"last_error":"SSL_read: 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","logging","logging-library"],"created_at":"2026-01-17T14:21:37.401Z","updated_at":"2026-01-17T14:21:37.467Z","avatar_url":"https://github.com/j-keck.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"#+TITLE: plog (pico log) - golang logging library\n#+PROPERTY: header-args :eval never-export\n\n[[https://pkg.go.dev/github.com/j-keck/plog][file:https://godoc.org/github.com/j-keck/plog?status.svg]]\n[[https://github.com/j-keck/plog/actions][file:https://github.com/j-keck/plog/workflows/test/badge.svg]]\n\n\n* Intro\n\npico log - because it's so small and has zero dependencies.\n\n** Why?\n\n I want a logging library with\n\n   - zero dependencies\n   - easy to use\n   - can emit log messages per go channel\n\n** Non Goals\n\n - blazing fast\n - a lot of features\n\n** Features\n\n  - console logging\n\n  - log over go channel\n\n  - optional global logger instance\n    (see [[#create-a-global-logger-instance][Create a global logger instance]])\n\n  - log output format configurable \\\\\n    (see [[#custom-log-format][Custom log format]], [[#log-output-format-per-program-arguments][Log output format per program arguments]] for examples)\n\n  - helper functions to set log level per command line arguments \\\\\n    (see [[#set-loglevel-per-program-arguments][Set LogLevel per program arguments]] for examples)\n\n\n* Usage\n\n/After each code block you will see an output example./\n\n** Create a console logger instance\n\nYou create a console logger per ~plog.NewDefaultConsoleLogger~ or ~plog.NewConsoleLogger~.\n\n*** ~plog.NewDefaultConsoleLogger()~\n\nThis function creates a console logger where each log column are separated with \" | \"\nand three log columns: the timestamp of the log event, the log level for the message\nand the log message.\n\n#+BEGIN_SRC go -r :tangle examples/console.go :exports both\n  package main\n\n  import  \"github.com/j-keck/plog\"\n\n  func main() {\n      log := plog.NewDefaultConsoleLogger()\n\n      log.Info(\"startup\")\n      log.Debug(\"change to debug level\")\n      log.SetLevel(plog.Debug)\n      log.Debug(\"level changed\")\n      log.Infof(\"2 + 2 = %d\", 2 + 2)\n  }\n#+END_SRC\n\n#+RESULTS:\n: Wed Feb 19 09:34:16 CET 2020 |  INFO | startup\n: Wed Feb 19 09:34:16 CET 2020 | DEBUG | level changed\n: Wed Feb 19 09:34:16 CET 2020 |  INFO | 2 + 2 = 4\n\n\n*** ~plog.NewConsoleLogger(separator string, formatters ...plog.Formatter)~\n\nThis function creates a logger with a custom log output format.\n\nThe first argument is a separator with separates each log column,\nthe rest are \"column formatters\". These describes which columns\nand how this columns are formatted (see [[#formatters][Formatters]] for more information).\n\n  #+BEGIN_SRC go -r :tangle examples/console-custom-format.go :exports both\n    package main\n\n    import  \"github.com/j-keck/plog\"\n\n    func main() {\n        log := plog.NewConsoleLogger(\n            \" - \",\n            plog.Level,\n            plog.TimestampMillis,\n            plog.Message,\n        )\n\n        // set log prefix and suffix\n        log.SetLogPrefix(\"[\").SetLogSuffix(\"]\")\n\n        log.Info(\"startup\")\n        log.Debug(\"change to debug level\")\n        log.SetLevel(plog.Debug)\n        log.Debug(\"level changed\")\n        log.Infof(\"2 + 2 = %d\", 2 + 2)\n    }\n  #+END_SRC\n\n  #+RESULTS:\n  : [ INFO - Feb 19 09:34:17.009 - startup]\n  : [DEBUG - Feb 19 09:34:17.010 - level changed]\n  : [ INFO - Feb 19 09:34:17.010 - 2 + 2 = 4]\n\n** Create a global logger instance\n\nYou create a singleton global logger instance per ~plog.GlobalLogger~.\nSo you can configure the log output only once, and every other ~plog.GlobalLogger~\ninstance have the same logging configuration.\n\nWhen you create a global logger, you *must* attach a console or stream logger to it.\nIf not, a warning is logged (this can be disabled with ~plog.DropUnhandledMessages~).\n\n~plog.GlobalLogger~ is a broadcast logger, so you can add many consumer.\n\n#+BEGIN_SRC go :tangle examples/global-logger.go :eval no\npackage main\n\nimport \"github.com/j-keck/plog\"\n\nfunc main() {\n  // initialize the logger\n  log := plog.GlobalLogger().Add(plog.NewDefaultConsoleLogger())\n  log.Info(\"in 'main'\")\n\n  other()\n}\n\nfunc other() {\n  log := plog.GlobalLogger()\n  log.Info(\"in 'other'\")\n}\n#+END_SRC\n\n#+BEGIN_SRC shell :results output :exports both\ngo run examples/global-logger.go\n#+END_SRC\n\n#+RESULTS:\n: Wed Feb 19 09:34:17 CET 2020 |  INFO | in 'main'\n: Wed Feb 19 09:34:17 CET 2020 |  INFO | in 'other'\n\n\n* API\n\nEach logger instance have the following functions:\n\n  | ~SetLevel(LogLevel)~                               | Set the log level. From ~plog.Trace~ to ~plog.Error~ |\n  | ~IsTraceEnabled()~                                 | Checks if the Trace level is enabled                 |\n  | ~IsDebugEnabled()~                                 | Checks if the Debug level is enabled                 |\n  | ~IsInfoEnabled()~                                  | Checks if the Info level is enabled                  |\n  | ~IsNoteEnabled()~                                  | Checks if the Note level is enabled                  |\n  | ~IsWarnEnabled()~                                  | Checks if the Warn level is enabled                  |\n  | ~IsErrorEnabled()~                                 | Checks if the Error level is enabled                 |\n  | ~Trace(string)~ / ~Tracef(string, ...{}interface)~ | Trace logging                                        |\n  | ~Debug(string)~ / ~Debugf(string, ...{}interface)~ | Debug logging                                        |\n  | ~Info(string)~ / ~Infof(string, ...{}interface)~   | Info logging                                         |\n  | ~Note(string)~ / ~Notef(string, ...{}interface)~   | Note (Notifications) logging                         |\n  | ~Warn(string)~ / ~Warnf(string, ...{}interface)~   | Warn logging                                         |\n  | ~Error(string)~ / ~Errorf(string, ...{}interface)~ | Error logging                                        |\n  | ~Fatal(string)~ / ~Fatalf(string, ...{}interface)~ | Fatal logging                                        |\n\nWhere the log functions act like ~fmt.Print(string)~ and ~fmt.Printf(string, ...{}interface)~.\n\n\n*** Console logger API\n\nThe ~consoleLogger~ has the following additional functions:\n\n  | ~SetStdout(io.Writer)~       | Redirect stdout                                |\n  | ~SetStderr(io.Writer)~       | Redirect stderr                                |\n  | ~SetLogPrefix(string)~       | Prepend the given string on each log message   |\n  | ~SetLogSuffix(string)~       | Append the given string on each log message    |\n  | ~AddLogFormatter(Formatter)~ | Add an log formatter to format the log message |\n\n\n*** Stream logger API\n\nThe ~streamLogger~ has the following additional functions:\n\n| ~SetStderr(io.Writer)~                        | Redirect stderr                                        |\n| ~Subscribe(bufferSize int) \u003c-chan LogMessage~ | Get a go channel where the log messages are emitted    |\n| ~WaitForSubscribers(timeout time.Duration)~   | Blocks till all subscribers have received all messages |\n\n\n*** Broadcast logger API\nThe ~broadcastLogger~ has the following additional functions:\n\n| ~Add(Logger)~ | Add a logger which receives the log messages |\n| ~Reset()~     | Reset removes all attached logger instances  |\n\n** Set the log level per programm arguments\n\n *plog* provides two helper functions to configure the LogLevel per program arguments:\n\n   - ~plog.FlagDebugVar(p *LogLevel, name string, usage string)~\n   - ~plog.FlagTraceVar(p *LogLevel, name string, usage string)~\n\n see [[#set-loglevel-per-program-arguments][Set LogLevel per program arguments]] for a example.\n\n\n** Formatters\n\n Formatters describes which and how each log column are logged.\n\n To define the format of the log message, you can use predefined formatters\n or construct your own.\n\n***** Predefined formatter\n\n  #+BEGIN_SRC go :imports '(\"github.com/j-keck/plog\" \"time\" \"fmt\" \"strings\") :exports results\n    msg := plog.LogMessage{plog.Info, time.Now(), \"go_srcfile\", 33, \"Test\"}\n    show := func(name string, formatter plog.Formatter) {\n      fmt.Printf(\"%-46s | '%s'\\n\", name, formatter.Format(\u0026msg))\n    }\n    fmt.Printf(\"%-46s | example output\\n%s\\n\", \"formatter\", strings.Repeat(\"-\", 80))\n    show(\"plog.Level\", plog.Level)\n    show(\"plog.Timestamp\", plog.Timestamp)\n    show(\"plog.TimestampMillis\", plog.TimestampMillis)\n    show(\"plog.TimestampUnixDate\", plog.TimestampUnixDate)\n    show(\"plog.Location\", plog.Location)\n    show(\"plog.File\", plog.File)\n    show(\"plog.Line\", plog.Line)\n    show(\"plog.Message\", plog.Message)\n  #+END_SRC\n\n  #+RESULTS:\n  #+begin_example\n  formatter                                      | example output\n  --------------------------------------------------------------------------------\n  plog.Level                                     | ' INFO'\n  plog.Timestamp                                 | 'Feb 19 09:34:17'\n  plog.TimestampMillis                           | 'Feb 19 09:34:17.855'\n  plog.TimestampUnixDate                         | 'Wed Feb 19 09:34:17 CET 2020'\n  plog.Location                                  | '     go_srcfile:33 '\n  plog.File                                      | '     go_srcfile'\n  plog.Line                                      | '33 '\n  plog.Message                                   | 'Test'\n  #+end_example\n\n\n***** Custom Columns\n\nA custom formatter expects a format string, which describes how each log column are formatted.\n\nThe ~TimestampFmt~ formatter used ~time.Format(format string)~ to format the\ntimestamp column. See the [[https://golang.org/pkg/time/#Time.Format][time.Format]] api for a description.\n\nThe ~LineFmt~ formatter expects a ~%d~ in his format where the line number\nshould be inserted.\n\nAll other formatters expects a ~%s~ where the value should be inserted.\n\n  #+BEGIN_SRC go :imports '(\"github.com/j-keck/plog\" \"time\" \"fmt\" \"strings\") :exports results\n    msg := plog.LogMessage{plog.Info, time.Now(), \"go_srcfile\", 33, \"Test\"}\n    show := func(name string, formatter plog.Formatter) {\n      fmt.Printf(\"%-46s | '%s'\\n\", name, formatter.Format(\u0026msg))\n    }\n    fmt.Printf(\"%-46s | example output\\n%s\\n\", \"formatter examples\", strings.Repeat(\"-\", 80))\n    show(\"plog.LevelFmt(\\\"%10s\\\")\", plog.LevelFmt(\"(%10s)\"))\n    show(\"plog.TimestampFmt(\\\"15:04:05.000\\\")\", plog.TimestampFmt(\"15:04:05.000\"))\n    show(\"plog.TimestampFmt(\\\"2006-01-02T15:04:05Z07:00\\\")\", plog.TimestampFmt(\"2006-01-02T15:04:05Z07:00\"))\n    show(\"plog.LocationFmt(\\\"[file: %s, line: %d]\\\")\", plog.LocationFmt(\"[file: %s, line: %d]\"))\n    show(\"plog.FileFmt(\\\"\u003c%s\u003e\\\")\", plog.FileFmt(\"\u003c%s\u003e\"))\n    show(\"plog.LineFmt(\\\"[%d]\\\")\", plog.LineFmt(\"[%d]\"))\n\n  #+END_SRC\n\n  #+RESULTS:\n  : formatter examples                             | example output\n  : --------------------------------------------------------------------------------\n  : plog.LevelFmt(\"%10s\")                          | '(      INFO)'\n  : plog.TimestampFmt(\"15:04:05.000\")              | '09:34:18.269'\n  : plog.TimestampFmt(\"2006-01-02T15:04:05Z07:00\") | '2020-02-19T09:34:18+01:00'\n  : plog.LocationFmt(\"[file: %s, line: %d]\")       | '[file: go_srcfile, line: 33]'\n  : plog.FileFmt(\"\u003c%s\u003e\")                           | '\u003cgo_srcfile\u003e'\n  : plog.LineFmt(\"[%d]\")                           | '[33]'\n\n\n\n* Examples\n\n** Custom log format\n\n  #+BEGIN_SRC go :tangle examples/logformat.go :eval no\n    package main\n\n    import \"github.com/j-keck/plog\"\n\n    func main() {\n        log := plog.NewConsoleLogger(\" - \",\n            plog.LevelFmt(\"(%-5s)\"),\n            plog.TimestampFmt(\"2006-01-02T15:04:05Z07:00\"),\n            plog.MessageFmt(\"%-20s\"),\n            plog.LocationFmt(\"%s[%d]\"),\n\n        )\n        log.SetLogPrefix(\"[\").SetLogSuffix(\"]\")\n\n        log.Info(\"startup\")\n        log.Debug(\"change to debug level\")\n        log.SetLevel(plog.Debug)\n        log.Debug(\"level changed\")\n        log.Infof(\"2 + 2 = %d\", 2 + 2)\n    }\n  #+END_SRC\n\n  #+BEGIN_SRC shell :results output :exports both\n  go run examples/logformat.go\n  #+END_SRC\n\n  #+RESULTS:\n  : [(INFO ) - 2020-02-19T09:34:18+01:00 - startup              - logformat[16]]\n  : [(DEBUG) - 2020-02-19T09:34:18+01:00 - level changed        - logformat[19]]\n  : [(INFO ) - 2020-02-19T09:34:18+01:00 - 2 + 2 = 4            - logformat[20]]\n\n\n\n** Log output format per program arguments\n\n#+BEGIN_SRC go :tangle examples/log-output-format-per-args.go :eval no\n  package main\n\n  import \"github.com/j-keck/plog\"\n  import \"flag\"\n\n  func main() {\n      //\n      // flags\n      //\n      logTs := flag.Bool(\"log-timestamps\", false, \"log messages with timestamps\")\n      logLocation := flag.Bool(\"log-location\", false, \"log messages with caller location\")\n      flag.Parse()\n\n      //\n      // initialize / configure the logger\n      //\n      log := plog.NewConsoleLogger(\" | \")\n\n      // timestamp only when '-log-timestamps' flag is given\n      if *logTs {\n          log.AddLogFormatter(plog.TimestampUnixDate)\n      }\n\n      // log level\n      log.AddLogFormatter(plog.Level)\n\n      // location only when '-log-location' flag is given\n      if *logLocation {\n          log.AddLogFormatter(plog.Location)\n      }\n\n      // log message\n      log.AddLogFormatter(plog.Message)\n\n\n      //\n      // action\n      //\n      log.Info(\"startup\")\n      log.Debug(\"change to debug level\")\n      log.SetLevel(plog.Debug)\n      log.Debug(\"level changed\")\n      log.Infof(\"2 + 2 = %d\", 2 + 2)\n  }\n#+END_SRC\n\n#+BEGIN_SRC shell :results output :exports results\nrun() { echo $(printf \"=%.0s\" {1..80}); echo \"j@main:~ ⟩ $@\"; $@; echo;}\n\nrun go run examples/log-output-format-per-args.go\nrun go run examples/log-output-format-per-args.go -log-timestamps\nrun go run examples/log-output-format-per-args.go -log-location\nrun go run examples/log-output-format-per-args.go -log-timestamps -log-location\n#+END_SRC\n\n#+RESULTS:\n#+begin_example\n================================================================================\nj@main:~ ⟩ go run examples/log-output-format-per-args.go\n INFO | startup\nDEBUG | level changed\n INFO | 2 + 2 = 4\n\n================================================================================\nj@main:~ ⟩ go run examples/log-output-format-per-args.go -log-timestamps\nWed Feb 19 09:34:19 CET 2020 |  INFO | startup\nWed Feb 19 09:34:19 CET 2020 | DEBUG | level changed\nWed Feb 19 09:34:19 CET 2020 |  INFO | 2 + 2 = 4\n\n================================================================================\nj@main:~ ⟩ go run examples/log-output-format-per-args.go -log-location\n INFO | log-output-format-per-args:40  | startup\nDEBUG | log-output-format-per-args:43  | level changed\n INFO | log-output-format-per-args:44  | 2 + 2 = 4\n\n================================================================================\nj@main:~ ⟩ go run examples/log-output-format-per-args.go -log-timestamps -log-location\nWed Feb 19 09:34:20 CET 2020 |  INFO | log-output-format-per-args:40  | startup\nWed Feb 19 09:34:20 CET 2020 | DEBUG | log-output-format-per-args:43  | level changed\nWed Feb 19 09:34:20 CET 2020 |  INFO | log-output-format-per-args:44  | 2 + 2 = 4\n\n#+end_example\n\n\n** Set LogLevel per program arguments\n\n#+BEGIN_SRC go :tangle examples/loglevel-per-args.go :eval no\n  package main\n\n  import \"github.com/j-keck/plog\"\n  import \"flag\"\n\n  func main() {\n      log := plog.NewDefaultConsoleLogger()\n\n      logLevel := plog.Info\n      plog.FlagDebugVar(\u0026logLevel,  \"v\", \"debug\")\n      plog.FlagTraceVar(\u0026logLevel, \"vv\", \"trace\")\n      flag.Parse()\n\n      log.SetLevel(logLevel)\n\n      log.Info(\"info\")\n      log.Debug(\"debug\")\n      log.Trace(\"trace\")\n  }\n#+END_SRC\n\n\n#+BEGIN_SRC shell :results output :exports results\nrun() { echo $(printf \"=%.0s\" {1..80}); echo \"j@main:~ ⟩ $@\"; $@; echo;}\n\nrun go run examples/loglevel-per-args.go\nrun go run examples/loglevel-per-args.go -v\nrun go run examples/loglevel-per-args.go -vv\n#+END_SRC\n\n#+RESULTS:\n#+begin_example\n================================================================================\nj@main:~ ⟩ go run examples/loglevel-per-args.go\nWed Feb 19 09:34:20 CET 2020 |  INFO | info\n\n================================================================================\nj@main:~ ⟩ go run examples/loglevel-per-args.go -v\nWed Feb 19 09:34:20 CET 2020 |  INFO | info\nWed Feb 19 09:34:20 CET 2020 | DEBUG | debug\n\n================================================================================\nj@main:~ ⟩ go run examples/loglevel-per-args.go -vv\nWed Feb 19 09:34:21 CET 2020 |  INFO | info\nWed Feb 19 09:34:21 CET 2020 | DEBUG | debug\nWed Feb 19 09:34:21 CET 2020 | TRACE | trace\n\n#+end_example\n\n\n\n** Log over a go channel\n\n~plog.NewStreamLogger()~ creates a new streaming logger.\nWith ~Subscribe(bufferSize int) \u003c-chan LogMessage~ you get a go channel where\nthe log messages are emitted.\n\n#+BEGIN_SRC go :tangle examples/stream.go :eval no\n  package main\n\n  import \"github.com/j-keck/plog\"\n  import \"fmt\"\n  import \"time\"\n\n  func main() {\n      log := plog.NewStreamLogger()\n      logC := log.Subscribe(10)\n\n      log.Info(\"startup\")\n      log.Debug(\"change to debug level\")\n      log.SetLevel(plog.Debug)\n      log.Debug(\"level changed\")\n      log.Infof(\"2 + 2 = %d\", 2 + 2)\n\n      go func() {\n        for msg := range logC {\n          fmt.Printf(\"%s: %s\\n\", msg.Level, msg.Message)\n        }\n      }()\n\n      log.WaitForSubscribers(100 * time.Millisecond)\n  }\n#+END_SRC\n\n#+BEGIN_SRC shell :results output :exports both\ngo run examples/stream.go\n#+END_SRC\n\n#+RESULTS:\n: INFO: startup\n: DEBUG: level changed\n: INFO: 2 + 2 = 4\n\n\n** Broadcast log messages to multiple receivers.\n\nTo simplify the example, only console loggers are used,\nbut you can also use stream loggers.\n\n#+BEGIN_SRC go :tangle examples/broadcast.go :eval no\n  package main\n\n  import \"github.com/j-keck/plog\"\n\n  func main() {\n      log := plog.NewBroadcastLogger(\n          plog.NewDefaultConsoleLogger(),\n          plog.NewDefaultConsoleLogger(),\n          plog.NewDefaultConsoleLogger(),\n      )\n\n      log.Info(\"startup\")\n      log.Debug(\"change to debug level\")\n      log.SetLevel(plog.Debug)\n      log.Debug(\"level changed\")\n      log.Infof(\"2 + 2 = %d\", 2 + 2)\n  }\n#+END_SRC\n\n#+BEGIN_SRC shell :results output :exports both\ngo run examples/broadcast.go\n#+END_SRC\n\n#+RESULTS:\n: Wed Feb 19 09:34:22 CET 2020 |  INFO | startup\n: Wed Feb 19 09:34:22 CET 2020 |  INFO | startup\n: Wed Feb 19 09:34:22 CET 2020 |  INFO | startup\n: Wed Feb 19 09:34:22 CET 2020 | DEBUG | level changed\n: Wed Feb 19 09:34:22 CET 2020 | DEBUG | level changed\n: Wed Feb 19 09:34:22 CET 2020 | DEBUG | level changed\n: Wed Feb 19 09:34:22 CET 2020 |  INFO | 2 + 2 = 4\n: Wed Feb 19 09:34:22 CET 2020 |  INFO | 2 + 2 = 4\n: Wed Feb 19 09:34:22 CET 2020 |  INFO | 2 + 2 = 4\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fj-keck%2Fplog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fj-keck%2Fplog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fj-keck%2Fplog/lists"}