{"id":19719933,"url":"https://github.com/timboudreau/bunyan-java","last_synced_at":"2025-04-29T21:30:42.336Z","repository":{"id":14980860,"uuid":"17706015","full_name":"timboudreau/bunyan-java","owner":"timboudreau","description":"A little logging library that uses the format of NodeJS's bunyan JSON logger","archived":false,"fork":false,"pushed_at":"2020-08-10T17:56:23.000Z","size":355,"stargazers_count":7,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-05T19:23:45.096Z","etag":null,"topics":["bunyan","java","json","json-logger","logging"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/timboudreau.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-03-13T10:22:10.000Z","updated_at":"2022-07-05T21:22:46.000Z","dependencies_parsed_at":"2022-09-26T21:50:50.261Z","dependency_job_id":null,"html_url":"https://github.com/timboudreau/bunyan-java","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timboudreau%2Fbunyan-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timboudreau%2Fbunyan-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timboudreau%2Fbunyan-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timboudreau%2Fbunyan-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/timboudreau","download_url":"https://codeload.github.com/timboudreau/bunyan-java/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251585739,"owners_count":21613270,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["bunyan","java","json","json-logger","logging"],"created_at":"2024-11-11T23:09:44.579Z","updated_at":"2025-04-29T21:30:41.993Z","avatar_url":"https://github.com/timboudreau.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"bunyan-java (original - obsoleted by bunyan-java-v2)\n=========================================\n\n__This project has been replaced with [bunyan-java-v2 which simplifies its API](https://github.com/timboudreau/bunyan-java-v2) which should be used instead__\n\nAn opinionated implementation of a simple logger in Java whose output is compatible with\n[bunyan](https://github.com/trentm/node-bunyan), the excellent JSON\nlogger for [NodeJS](http://nodejs.org).\n\nUses [Guice](https://code.google.com/p/google-guice/) for injection, and has a fluent interface\nand support for using ``@Named`` to inject named loggers.  Uses \n[AutoCloseable](http://timboudreau.com/blog/AutoCloseable/read) to enable a log record to\nbe appended to, builder-style, and automatically written when its ``close()`` method is\nimplicitly or explicitly called.\n\n\n        class LogUser {\n           private final Logger logger;\n           LogUser(@Named(\"whatzit\") Logger logger) {\n              try (Log\u003cDebug\u003e log = logger.debug(\"someTask\")) {\n                  log.add(\"append to the message\");\n                  log.add(someObject);\n                  log.add(\"foo\", \"bar\");\n              }\n           }\n        }\n\nFile or console logging or both are available, others can be implemented.\n\n\nDependencies\n------------\n\nGuice, Giulius, Jackson\n\nYou do not have to use Giulius, but the default ``LogWriter`` implementation expects to find\nan instance of ``Settings`` bound.  If you want to use plain Guice, you'll need to implement\n``LogWriter`` or provide a \n[Settings](http://timboudreau.com/builds/job/mastfrog-parent/lastSuccessfulBuild/artifact/giulius-modules/giulius-parent/giulius-settings/target/apidocs/com/mastfrog/settings/Settings.html).\n\nIt is also useful to include giulius-jackson's ``JacksonModule``, which will automatically\nfind and bind a Jackson module that adds an improved serializer for ``Throwable``s.\n\nIntegration With Logging Frameworks\n-----------------------------------\n\nMost logging frameworks have a concept of \"appenders\" or \"handlers\" which write output to some\ndestination.  Several subprojects here can be used to install bunyan-java as a logging destination.\n\n * bunyan-java-log4j-appender - an appender for Log4J 1.x\n * bunyan-java-util-logging - a Handler implementation for the JDK's logging library\n * bunyan-log4j2-appender - an appender for Log4J 2.x - pass `-Dlog4j.configurationFactory=com.mastfrog.bunyan.log4j2.appender.BunyanConfigurationFactory` to use\n\nEach of these projects contains a Guice module which connects the logger to bunyan-java.  If you\nuse these adapters _you must also install the corresponding Guice module_ - logging prior to bunyan-java\nbeing initialized is buffered and output to bunyan-java on initialization; if bunyan-java never gets initialized,\nall logging will be buffered in-memory until there is no more memory.  For each framework, the\nmodule optionally (constructor argument) will _attempt_ to reinitialize the logging framework to\nuse bunyan-java with no configuration files needed.  This is great to get the basics working, but to\nensure *all* logging goes through bunyan-java, configure your logging framework of choice appropriately\n(usually system properties or files on disk or some combination thereof).\n\nNote that `java.util.logging` and Log4J are _text-oriented_ as most traditional Java logging is,\nmeaning that their output is much less rich than you can get from using bunyan-java directly - but\nthese adapters make it possible to unify all logging to output through bunyan.\n\nNote you will still need to use `LoggingModule` to set up bunyan-java, in addition to adapter modules.\n\nDifferences from Traditional Loggers\n------------------------------------\n\n### Designed for Dependency Injection\n\n * Bunyan-java is designed with dependency injection in mind, and utilizes Guice internally (you don't have to) - you can, for example,\nduring setup call `loggingModule.bindLogger(\"request\")`, and then anything that needs an instance of `Logger` can just ask for\n`@Named(\"request\") Logger logger`\n\n * Log objects, not text - most logging information is processed by machines anyway - single lines of JSON make far more sense as an output format\nthan lines of plain text\n\n * A log level is an object - and it's a factory for `Log` instances\n\n * A `Log` instance represents one Log record you are going to write, and calling `close()` on it writes it - using the JDK's `AutoCloseable` to ensure it is:\n\n```\ntry (Log\u003cDebug\u003e log = loggers.debug(\"saveFile\")) {\n   File newFile = findUnusedFile();\n   log.add(\"to\", newFile);\n   // do some complicated logic here, and add different properties to the log record depending what happens\n}\n```\n\nUsage\n-----\n\nLogging is configured using [Giulius](https://github.com/timboudreau/giulius) settings\nAPI, which by default uses properties files which may be in ``/etc/``, ``~/`` and/or\n``./``.  If you do not bind your own implementation of ``LogWriter``, the default \none is affected by these properties:\n\n * ``log.file`` - if set to a file path, log to this file instead of the console\n * ``log.console`` - also log to the console, even if a file is set\n * ``log.async`` - write log records out on a background thread, so the caller is not blocked\n   * A VM shutdown hook ensures that if the VM is not brutally killed, all pending log records are\nflushed synchronously during shutdown\n * ``log.level`` - the level of log below which log records should be discarded\n\nA Guice module, ``LoggingModule`` is provided, which makes it easy to use Guice's ``@Named``\nto inject loggers:\n\n\t\tSettings s = new SettingsBuilder(\"app-name\").addDefaultLocations().build();\n                LoggingModule mod = new LoggingModule().bindLogger(\"mailer\");\n\n\t\tDependencies deps = Dependencies.builder().add(Namespace.DEFAULT, s).add(new LoggingModule());\n                \n\t\t// ... then\n\n\t\tclass Mailer {\n                   Mailer (@Named(\"mailer\") Logger logger, ...) { ...\n\nNote: ``log.file`` console logging off uses buffered NIO - log records will be buffered, so logging may appear to stutter (a shutdown\nhook will ensure any buffered records are written) - and can write two million records in about 10 seconds on a laptop with an SSD.\n`log.async` is useful for performance if you will log to both console and a file, but uses a different file logging implementation.\n\n[This unit test](https://github.com/timboudreau/bunyan-java/blob/master/src/test/java/com/mastfrog/bunyan/LoggerTest.java) shows\nsome usage.  It results in output which, indeed, can be parsed nicely with Bunyan:\n\n![alt text](screen.png \"Bunyan parsing a log generated with this library\")\n\n\nClasses\n-------\n\nWe're aiming for simplicity more than flexibility here.  The following classes may be useful:\n\n * ``Loggers`` - A thing you get a logger from, injected by Guice, e.g. ``Logger logger = loggers.logger(\"whatever\");``;\ncontains final fields for all known log levels\n * ``Logger`` - A thing which can create a ``Log`` tied to a particular level\n * ``Log`` - A thing which you add objects and key-value pairs to, which becomes one line of logging - one log record.\nIt implements an exception-free variant of the JDK's ``AutoClosable`` - the natural way to use it is within a \n*try-with-resources* block as shown above;  at the close of that block, the log record is written out\n\nIf you want to ship log records someplace special, you can implement and bind ``LogWriter``, which has one method,\n``write(String)``.\n\n### Log Levels are Objects\n\nYou may notice that log levels are actual objects - not constants.  So when you get a debug logger, you get a \n``Log\u003cDebug\u003e``, and so forth.\n\nYou can actually also start from a log level to create a ``Log``, e.g.\n\n\t\t@Inject\n\t\tMyThing(Loggers loggers) {\n\t\t\ttry (Log\u003cDebug\u003e log = loggers.DEBUG.logger(\"stuff\")) {\n\t\t\t\tlog.add(\"This is the message\");\n\t\t\t\tlog.add(\"key\", \"value\");\n\t\t\t} // log gets written out here!\n\t\t}\n\n\nBut What About Static Logging?\n------------------------------\n\nYou don't need it.  I said this library was opinionated, right?\n\n\nMongoDB Log Sink\n----------------\n\nThe experimental subproject `bunyan-java-mongodb-sink` provides an implementation of bunyan-java's `LogSink` which\nwill route all logging to MongoDB.  This can be used in the following ways:\n\n * To route all logging to MongoDB, period, bind `LogSink` to `MongoDBLogSink` (there will be no console or other logging, no matter what you configured bunyan-java to do)\n * To use existing logging configuration, *and* MongoDB, bind `ComposableMongoDBSink` as an eager singleton, and call `LoggingModule.bindMultiLogSink()` when setting up your logging\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimboudreau%2Fbunyan-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimboudreau%2Fbunyan-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimboudreau%2Fbunyan-java/lists"}