{"id":21177616,"url":"https://github.com/tersesystems/echopraxia","last_synced_at":"2025-04-04T07:06:51.142Z","repository":{"id":36981149,"uuid":"435334568","full_name":"tersesystems/echopraxia","owner":"tersesystems","description":"Java Structured Logging API for Logback, Log4J2, and JUL","archived":false,"fork":false,"pushed_at":"2025-02-20T17:55:26.000Z","size":2446,"stargazers_count":55,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-28T06:07:38.585Z","etag":null,"topics":["conditional-logging","contextual-logging","java","logback","logging","slf4j","structured-logging"],"latest_commit_sha":null,"homepage":"https://tersesystems.github.io/echopraxia/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tersesystems.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2021-12-06T02:22:48.000Z","updated_at":"2025-01-14T18:26:31.000Z","dependencies_parsed_at":"2024-01-03T01:21:17.963Z","dependency_job_id":"fffd295d-f441-4f20-bb8f-552c4dacef50","html_url":"https://github.com/tersesystems/echopraxia","commit_stats":null,"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tersesystems%2Fechopraxia","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tersesystems%2Fechopraxia/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tersesystems%2Fechopraxia/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tersesystems%2Fechopraxia/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tersesystems","download_url":"https://codeload.github.com/tersesystems/echopraxia/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247135144,"owners_count":20889421,"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":["conditional-logging","contextual-logging","java","logback","logging","slf4j","structured-logging"],"created_at":"2024-11-20T17:16:36.849Z","updated_at":"2025-04-04T07:06:51.124Z","avatar_url":"https://github.com/tersesystems.png","language":"Java","funding_links":[],"categories":["项目","日志库","Projects"],"sub_categories":["日志记录","Logging"],"readme":"\n\u003c!---freshmark shields\noutput = [\n\tlink(shield('mvnrepository', 'mvnrepository', '{{group}}', 'blue'), 'https://mvnrepository.com/artifact/{{group}}'),\n\tlink(shield('License Apache', 'license', 'Apache', 'blue'), 'https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)'),\n\t].join('\\n')\n--\u003e\n[![mvnrepository](https://img.shields.io/badge/mvnrepository-com.tersesystems.echopraxia-blue.svg)](https://mvnrepository.com/artifact/com.tersesystems.echopraxia)\n[![License Apache](https://img.shields.io/badge/license-Apache-blue.svg)](https://tldrlegal.com/license/apache-license-2.0-(apache-2.0))\n\u003c!---freshmark /shields --\u003e\n# Echopraxia\n\n[Echopraxia](https://github.com/tersesystems/echopraxia) is a Java logging API designed around structured logging.  \n\nWhat this means is that all arguments in a logging statement have a name and a value, for example:\n\n```java\nvar fb = logger.fieldBuilder();\nlogger.info(\"arg1 is {} and arg2 is {}\", fb.list(\n  fb.string(\"name\", \"value\"),\n  fb.number(\"age\", 13)\n));\n```\n\nwrites out in logfmt as:\n\n```\nINFO 13.232 arg1 is name=value and arg2 is age=13\n```\n\nand in a JSON format as:\n\n```json\n{\n  \"message\": \"arg1 is name=value and arg2 is age=13\",\n  \"name\": \"value\",\n  \"age\": 13\n}\n```\n\nWhat makes Echopraxia effective -- especially in debugging -- is that you can define your own mappings, and then pass in your own objects and render complex objects.  For example, we can render a `Person` object:\n\n```java\nimport echopraxia.simple.*;\n\nvar fb = PersonFieldBuilder.instance();\nvar logger = LoggerFactory.getLogger(getClass());\n\nPerson abe = new Person(\"Abe\", 1, \"yodelling\");\nabe.setFather(new Person(\"Bert\", 35, \"keyboards\"));\nabe.setMother(new Person(\"Candace\", 30, \"iceskating\"));\n\nlogger.info(\"{}\", fb.person(\"abe\", abe));\n```\n\nAnd print out the internal state of the `Person` in both logfmt and JSON.\n\n```\nINFO 13.223 abe={Abe, 1, father={Bert, 35, father=null, mother=null, interests=[keyboards]}, mother={Candace, 30, father=null, mother=null, interests=[iceskating]}, interests=[yodelling]}\n```\n\n## Fields\n\nEchopraxia also has a \"contextual\" logging feature that renders fields in JSON:\n\n```java\nvar fooLogger = logger.withFields(fb.string(\"foo\", \"bar\"));\nfooLogger.info(\"This logs the 'foo' field automatically in JSON\");\n```\n\n## Conditions\n\nAnd has conditional logging based on fields and exceptions, optionally using JSONPath:\n\n```java\nimport echopraxia.logging.api.*;\n\nJsonPathCondition c = JsonPathCondition.pathCondition((level, ctx) -\u003e\n    ctx.findString(\"$.exception.stackTrace[0].methodName\")\n        .filter(s -\u003e s.endsWith(\"Foo\"))\n        .isPresent());\nlogger.withCondition(c).error(\"Only render this error if method name ends in Foo\", e);\n```\n\nThere is also a feature to change logging conditions [dynamically using scripts](https://github.com/tersesystems/smallest-dynamic-logging-example).\n\n## Custom Loggers\n\nExtending the `Logger` class with your own methods is very straightforward.\n\n```java\nimport echopraxia.api.FieldBuilder;\nimport echopraxia.logging.api.*;\nimport echopraxia.logging.spi.*;\nimport echopraxia.simple.Logger;\n\nclass MyLoggerFactory {\n  public static class MyFieldBuilder implements FieldBuilder {\n    // Add your own field builder methods in here\n  }\n\n  private static final MyFieldBuilder fieldBuilder = new MyFieldBuilder();\n\n  public static MyLogger getLogger(Class\u003c?\u003e clazz) {\n    final CoreLogger core = CoreLoggerFactory.getLogger(Logger.class.getName(), clazz);\n    return new MyLogger(core);\n  }\n\n  public static final class MyLogger extends Logger {\n    public static final String FQCN = MyLogger.class.getName();\n\n    public MyLogger(CoreLogger logger) {\n      super(logger);\n    }\n\n    @Override\n    public FieldBuilder fieldBuilder() {\n      return fieldBuilder;\n    }\n\n    public void notice(String message) {\n      // the caller is MyLogger specifically, so we need to let the logging framework know how to\n      // address it.\n      core().withFQCN(FQCN).log(Level.INFO, message, fb -\u003e fb.bool(\"notice\", true), fieldBuilder());\n    }\n  }\n}\n\nclass Main {\n  private static final MyLoggerFactory.MyLogger logger = MyLoggerFactory.getLogger(Main.class);\n\n  public static void main(String[] args) {\n    logger.notice(\"this has a notice field added\");\n  }\n}\n```\n\n## Documentation\n\nPlease see the [online documentation](https://tersesystems.github.io/echopraxia).\n\n## Examples\n\nFor the fastest possible way to try out Echopraxia, download and run the [JBang script](https://github.com/tersesystems/smallest-dynamic-logging-example/blob/main/jbang/Script.java).\n\nSimple examples and integrations with [dropwizard metrics](https://metrics.dropwizard.io/4.2.0/) and [OSHI](https://github.com/oshi/oshi) are available at [echopraxia-examples](https://github.com/tersesystems/echopraxia-examples).\n\nFor a web application example, see this [Spring Boot Project](https://github.com/tersesystems/echopraxia-spring-boot-example).\n\n## Scala API\n\nThere is a Scala API available at [https://github.com/tersesystems/echopraxia-plusscala](https://github.com/tersesystems/echopraxia-plusscala).\n\n## Benchmarks\n\nBenchmarks are available at [BENCHMARKS.md](BENCHMARKS.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftersesystems%2Fechopraxia","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftersesystems%2Fechopraxia","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftersesystems%2Fechopraxia/lists"}