{"id":19765683,"url":"https://github.com/openhft/chronicle-logger","last_synced_at":"2025-04-05T21:08:48.086Z","repository":{"id":19028411,"uuid":"22252491","full_name":"OpenHFT/Chronicle-Logger","owner":"OpenHFT","description":"A sub microsecond java logger, supporting standard logging APIs such as Slf \u0026 Log4J","archived":false,"fork":false,"pushed_at":"2024-05-29T07:45:50.000Z","size":7984,"stargazers_count":223,"open_issues_count":5,"forks_count":63,"subscribers_count":39,"default_branch":"ea","last_synced_at":"2024-05-29T07:54:16.269Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://chronicle.software/products/chronicle-logger/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OpenHFT.png","metadata":{"files":{"readme":"README.adoc","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}},"created_at":"2014-07-25T09:54:29.000Z","updated_at":"2024-05-28T18:57:05.000Z","dependencies_parsed_at":"2023-01-14T12:56:08.436Z","dependency_job_id":"f1fa4381-3d9f-4169-811c-2b543dd770f1","html_url":"https://github.com/OpenHFT/Chronicle-Logger","commit_stats":null,"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenHFT%2FChronicle-Logger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenHFT%2FChronicle-Logger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenHFT%2FChronicle-Logger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenHFT%2FChronicle-Logger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OpenHFT","download_url":"https://codeload.github.com/OpenHFT/Chronicle-Logger/tar.gz/refs/heads/ea","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247399877,"owners_count":20932876,"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":[],"created_at":"2024-11-12T04:19:04.003Z","updated_at":"2025-04-05T21:08:48.066Z","avatar_url":"https://github.com/OpenHFT.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"= Chronicle Logger\nChronicle Software\n:css-signature: demo\n:toc: macro\n:toclevels: 2\n:icons: font\n\nimage:https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-logger/badge.svg[caption=\"\",link=https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-logger]\nimage:https://javadoc.io/badge2/net.openhft/chronicle-logger/javadoc.svg[link=\"https://www.javadoc.io/doc/net.openhft/chronicle-logger/latest/index.html\"]\n//image:https://javadoc-badge.appspot.com/net.openhft/chronicle-wire.svg?label=javadoc[JavaDoc, link=https://www.javadoc.io/doc/net.openhft/chronicle-logger]\nimage:https://img.shields.io/github/license/OpenHFT/Chronicle-Logger[GitHub]\nimage:https://img.shields.io/badge/release%20notes-subscribe-brightgreen[link=\"https://chronicle.software/release-notes/\"]\nimage:https://sonarcloud.io/api/project_badges/measure?project=OpenHFT_Chronicle-Logger\u0026metric=alert_status[link=\"https://sonarcloud.io/dashboard?id=OpenHFT_Chronicle-Logger\"]\n\nimage::docs/images/Logger_line.png[width=20%]\n\ntoc::[]\n\n== About\n\n=== Version\n\n[#image-maven]\n[caption=\"\", link=https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-logger]\nimage::https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-logger/badge.svg[]\n\n== Overview\n\nToday most programs require the logging of large amounts of data, especially in trading systems where this is a \nregulatory requirement. Loggers can affect your system performance, therefore logging is sometimes kept to a minimum.\nWith Chronicle Logger we aim to minimize logging overhead, freeing your system to focus on the business logic.\n\nChronicle logger supports most of the standard logging API’s including: \n\n* \u003c\u003cchronicle-logger-slf4j, SLF4J\u003e\u003e\n* \u003c\u003cchronicle-logger-logback, Logback\u003e\u003e\n* \u003c\u003cchronicle-logger-log4j-1, Apache log4j 1.2\u003e\u003e\n* \u003c\u003cchronicle-logger-log4j-2, Apache log4j 2\u003e\u003e\n* \u003c\u003cchronicle-logger-jul, Java Util Logging\u003e\u003e\n* \u003c\u003cchronicle-logger-jcl, Apache Common Logging\u003e\u003e\n\nChronicle Logger is able to aggregate all your logs to a central store. It has built-in resilience, so you will never\nlose messages.\n\nAt the moment, Chronicle Logger only supports binary logs, which is beneficial for write speed but requires extra tools\nto read them. We provide some basic #tools[tools] for that and an API to develop your own.\n\nNOTE: `chronicle-logger-log4j-2` does not suffer from the log4shell vulnerability as it does not reuse the Log4J2 message formatting machinery\n\n== How it works\n\nChronicle Logger is built on top of Chronicle Queue. It provides multiple logging frameworks' adapters and is a low latency,\nhigh throughput synchronous writer. Unlike asynchronous writers, you will always see the last message before\nthe application dies, as usually it is the last message that is the most valuable.\n\n== Performance\n\nWe have run a benchmark to compare Chronicle Logger with normal file appender of Log4J2 (the quickest of mainstream\nlogging frameworks). Results below:\n\n|===\n|*Benchmark*                           |*Mode*|*Samples*|*Score*|*Score error*|*Units*\n\n|Chronicle Logger, simple message        |  avgt  |   5       |784.761  |  68.018       | ns/op\n|Chronicle Logger, message with Exception|  avgt  |   5       |12801.245|  417.695      | ns/op\n|Log4J2, simple message                  |  avgt  |   5       |2427.177 |  454.057      | ns/op\n|Log4J2, message with Exception          |  avgt  |   5       |17173.369|  3193.413     | ns/op\n|===\n\nTest Hardware:\n[source]\n----\nIntel Core i7-6700K\n32GB DDR4 RAM\n512GB M.2 PCI-e 3.0 x 4 NVMe SSD\n----\n\n== Bindings\n\nAll config files for bindings support limited variable interpolation where the variables are replaced with the \ncorresponding values from the same configuration file or the system properties. We have one predefined variable, `pid`,\nso `${pid}`  will replaced by current process id. System properties have the precedence in placeholder replacement \nso they can be overriden.\n\nThe following can be configured for each logger:\n\n|===\n| *Property* | *Description*                          | *Values*                       | *Per-Logger*\n\n| path          | the base directory of a Chronicle        |                                  | yes\n| level         | default log level                        | trace, debug, info, warn, error  | yes\n|===\n\nAdditionally, underlying Chronicle Queue can be tweaked by providing the following optional config properties:\n\n* `bufferCapacity`\n* `blockSize`\n* `rollCycle`\n\nIf set, these will override the default Chronicle Queue configuration. _Use with caution!_\n\n*Please Note*\n\n  * Loggers are not hierarchically grouped so `my.domain.package.MyClass1` and `my.domain` are two distinct entities.\n  * The `path` is used to track the underlying Chronicle Queue so having two loggers configured with the same `path` is unsupported\n\n=== chronicle-logger-slf4j\n\nThe chronicle-logger-slf4j is an implementation of SLF4J API \u003e 1.7.x.\n\nTo configure this sl4j binding you need to specify the location of a properties files (file-system or classpath) \nvia system properties:\n\n[source]\n----\n-Dchronicle.logger.properties=${pathToYourPropertiesFile}\n----\n\nAlternatively, you could use one of the default locations: `chronicle-logger.properties` \nor `config/chronicle-logger.properties` located in the classpath.\n\nThe default configuration is build using properties with `chronicle.logger.root` as prefix but you can also set \nper-logger settings i.e. `chronicle.logger.L1.*`\n\n==== Config Example\n\n[source, properties]\n----\n# shared properties\nchronicle.base                        = ${java.io.tmpdir}/chronicle-logs/${pid}\n\n# logger : default\nchronicle.logger.root.path            = ${slf4j.chronicle.base}/main\nchronicle.logger.root.level           = debug\n\n# optional tweaks\nchronicle.logger.root.cfg.bufferCapacity = 128\nchronicle.logger.root.cfg.blockSize      = 256\n\n# logger : L1\nchronicle.logger.L1.path              = ${slf4j.chronicle.base}/L1\nchronicle.logger.L1.level             = info\n----\n\n=== chronicle-logger-logback\n\nThe chronicle-logger-logback module provides appender for Logback: `net.openhft.chronicle.logger.logback.ChronicleAppender`\n\n==== Config Example\n  \n[source, xml]\n----\n\u003cappender name  = \"ChronicleAppender\"\n        class = \"net.openhft.chronicle.logger.logback.ChronicleAppender\"\u003e\n  \n  \u003c!-- Path used by the underlying ChronicleQueue --\u003e\n  \u003cpath\u003e${java.io.tmpdir}/ChronicleAppender\u003c/path\u003e\n\n  \u003c!--\n  Configure the underlying ChronicleQueue tweaks\n  --\u003e\n  \u003cchronicleConfig\u003e\n      \u003cblockSize\u003e128\u003c/blockSize\u003e\n  \u003c/chronicleConfig\u003e\n\u003c/appender\u003e\n----\n\n=== chronicle-logger-log4j-1\n\nWe provide log4j1 appender `net.openhft.chronicle.logger.log4j1.ChronicleAppender`\n\n==== Config Example\n\n[source, xml]\n----\n\u003c!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\"\u003e\n\u003clog4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'\u003e\n\n    \u003c!-- ******************************************************************* --\u003e\n    \u003c!--                                                                     --\u003e\n    \u003c!-- ******************************************************************* --\u003e\n\n    \u003cappender name  = \"CHRONICLE\"\n              class = \"net.openhft.chronicle.logger.log4j1.ChronicleAppender\"\u003e\n        \u003cparam name=\"path\" value=\"${java.io.tmpdir}/chronicle-log4j1/chronicle\"/\u003e\n    \u003c/appender\u003e\n\n    \u003c!-- ******************************************************************* --\u003e\n    \u003c!-- STDOUT                                                              --\u003e\n    \u003c!-- ******************************************************************* --\u003e\n\n    \u003cappender name  = \"STDOUT\"\n              class = \"org.apache.log4j.ConsoleAppender\"\u003e\n        \u003clayout class=\"org.apache.log4j.PatternLayout\"\u003e\n            \u003cparam name=\"ConversionPattern\" value=\"%-4r [%t] %-5p %c %x - %m%n\" /\u003e\n        \u003c/layout\u003e\n    \u003c/appender\u003e\n\n    \u003c!-- ******************************************************************* --\u003e\n    \u003c!--                                                                     --\u003e\n    \u003c!-- ******************************************************************* --\u003e\n\n    \u003clogger name=\"chronicle\" additivity=\"false\"\u003e\n        \u003clevel value=\"trace\"/\u003e\n        \u003cappender-ref ref=\"CHRONICLE\"/\u003e\n    \u003c/logger\u003e\n\n    \u003c!-- ******************************************************************* --\u003e\n    \u003c!--                                                                     --\u003e\n    \u003c!-- ******************************************************************* --\u003e\n\n    \u003clogger name=\"net.openhft\" additivity=\"false\"\u003e\n        \u003clevel value=\"warn\"/\u003e\n        \u003cappender-ref ref=\"STDOUT\"/\u003e\n    \u003c/logger\u003e\n\n    \u003c!-- ******************************************************************* --\u003e\n    \u003c!--                                                                     --\u003e\n    \u003c!-- ******************************************************************* --\u003e\n\n    \u003croot\u003e\n        \u003clevel value=\"debug\" /\u003e\n        \u003cappender-ref ref=\"STDOUT\" /\u003e\n    \u003c/root\u003e\n\n\u003c/log4j:configuration\u003e\n----\n\n=== chronicle-logger-log4j-2\n\nUse `\u003cChronicle/\u003e` element in `\u003cappenders/\u003e` to create Chronicle appender. Optional `\u003cchronicleCfg/\u003e` element can be\nused to tweak underlying Chronicle Queue.\n\n==== Config Example\n\n[source, xml]\n----\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cconfiguration packages=\"net.openhft.chronicle.logger,net.openhft.chronicle.logger.log4j2\"\u003e\n\n    \u003c!-- ******************************************************************* --\u003e\n    \u003c!-- APPENDERS                                                           --\u003e\n    \u003c!-- ******************************************************************* --\u003e\n\n    \u003cappenders\u003e\n\n        \u003cConsole name=\"STDOUT\" target=\"SYSTEM_OUT\"\u003e\n            \u003cPatternLayout pattern=\"[CHRONOLOGY] [%-5p] %c - %m%n%throwable{none}\"/\u003e\n        \u003c/Console\u003e\n\n        \u003cChronicle name=\"CHRONICLE\"\u003e\n            \u003cpath\u003e${sys:java.io.tmpdir}/chronicle-log4j2/binary-chronicle\u003c/path\u003e\n            \u003cchronicleCfg\u003e\n                \u003cblockSize\u003e128\u003c/blockSize\u003e\n                \u003cbufferCapacity\u003e256\u003c/bufferCapacity\u003e\n            \u003c/chronicleCfg\u003e\n        \u003c/Chronicle\u003e\n\n    \u003c/appenders\u003e\n\n    \u003c!-- ******************************************************************* --\u003e\n    \u003c!-- LOGGERS                                                             --\u003e\n    \u003c!-- ******************************************************************* --\u003e\n\n    \u003cloggers\u003e\n\n        \u003croot level=\"all\"\u003e\n            \u003cappender-ref ref=\"STDOUT\"/\u003e\n        \u003c/root\u003e\n\n        \u003clogger name=\"chronicle\" level=\"trace\" additivity=\"false\"\u003e\n            \u003cappender-ref ref=\"CHRONICLE\"/\u003e\n        \u003c/logger\u003e\n\n        \u003c!-- *************************************************************** --\u003e\n        \u003c!--                                                                 --\u003e\n        \u003c!-- *************************************************************** --\u003e\n\n        \u003clogger name=\"net.openhft\" level=\"warn\"/\u003e\n\n    \u003c/loggers\u003e\n\n\u003c/configuration\u003e\n----\n\n=== chronicle-logger-jul\n\nUse `net.openhft.chronicle.logger.jul.ChronicleHandler` as a handler\n\n==== Config Example\n\n[source, properties]\n----\nhandlers=java.util.logging.ConsoleHandler, net.openhft.chronicle.logger.jul.ChronicleHandler\n\n.level=ALL\n\njava.util.logging.ConsoleHandler.level=ALL\njava.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter\n\nnet.openhft.level=WARNING\nnet.openhft.handlers=java.util.logging.ConsoleHandler\n\nnet.openhft.chronicle.logger.jul.ChronicleHandler.path = ${java.io.tmpdir}/chronicle-jul\nnet.openhft.chronicle.logger.jul.ChronicleHandler.level = ALL\n\nchronicle.level=INFO\nchronicle.handlers=net.openhft.chronicle.logger.jul.ChronicleHandler\nchronicle.useParentHandlers=false\n----\n\n=== chronicle-logger-jcl\n\nSimilar to slf4j, to configure this binding you need to specify the location of a properties files (file-system or classpath) \nvia system properties:\n[source]\n----\n-Dchronicle.logger.properties=${pathToYourPropertiesFile}\n----\n\nAlternatively, you could use one of the default locations: `chronicle-logger.properties` \nor `config/chronicle-logger.properties` located in the classpath.\n\n==== Config Example\n\n[source, properties]\n----\nchronicle.logger.base             = ${java.io.tmpdir}/chronicle-jcl\nchronicle.logger.root.path        = ${chronicle.logger.base}/root\nchronicle.logger.root.level       = debug\n\n# logger : Logger1\nchronicle.logger.logger_1.path    = ${chronicle.logger.base}/logger_1\nchronicle.logger.logger_1.level   = info\n----\n\n=== Tools\n\n* `net.openhft.chronicle.logger.tools.ChroniCat` - tool to dump log contents to STDOUT\n[source]\n---\nChroniCat [-w \u003cwireType\u003e] \u003cpath\u003e\n    \u003cwireType\u003e - wire format, default BINARY_LIGHT\n    \u003cpath\u003e     - base path of Chronicle Logs storage\n\nmvn exec:java -Dexec.mainClass=\"net.openhft.chronicle.logger.tools.ChroniCat\" -Dexec.args=\"...\"\n---\n\n* `net.openhft.chronicle.logger.tools.ChroniTail` - same as ChroniCat but waits for more data, similar to *nix `tail` utility\n\n[source]\n----\nChroniTail [-w \u003cwireType\u003e] \u003cpath\u003e\n    \u003cwireType\u003e - wire format, default BINARY_LIGHT\n    \u003cpath\u003e     - base path of Chronicle Logs storage\n\nmvn exec:java -Dexec.mainClass=\"net.openhft.chronicle.logger.tools.ChroniTail\" -Dexec.args=\"...\"\n----\n\n* We also provide generic interface to interact with logs, `net.openhft.chronicle.logger.tools.ChronicleLogReader`,\nallowing arbitrary operations with decoded log lines. Please refer to javadocs.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenhft%2Fchronicle-logger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenhft%2Fchronicle-logger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenhft%2Fchronicle-logger/lists"}