{"id":18621270,"url":"https://github.com/sofastack/sofa-common-tools","last_synced_at":"2025-04-06T13:11:00.393Z","repository":{"id":33885225,"uuid":"124863824","full_name":"sofastack/sofa-common-tools","owner":"sofastack","description":"sofa-common-tools is a library that provide some utility functions to other SOFA libraries.","archived":false,"fork":false,"pushed_at":"2024-06-06T07:21:19.000Z","size":616,"stargazers_count":176,"open_issues_count":6,"forks_count":95,"subscribers_count":27,"default_branch":"master","last_synced_at":"2025-03-30T11:09:16.772Z","etag":null,"topics":["log4j","log4j2","logback","slf4j","sofastack"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"alipay/sofa-common-tools","license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sofastack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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":"2018-03-12T09:20:21.000Z","updated_at":"2024-12-22T13:38:24.000Z","dependencies_parsed_at":"2023-01-15T03:15:53.807Z","dependency_job_id":"cab6d4d5-a54c-4e48-8c33-52587a4d0e56","html_url":"https://github.com/sofastack/sofa-common-tools","commit_stats":null,"previous_names":["alipay/sofa-common-tools"],"tags_count":41,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sofastack%2Fsofa-common-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sofastack%2Fsofa-common-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sofastack%2Fsofa-common-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sofastack%2Fsofa-common-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sofastack","download_url":"https://codeload.github.com/sofastack/sofa-common-tools/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247485287,"owners_count":20946398,"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":["log4j","log4j2","logback","slf4j","sofastack"],"created_at":"2024-11-07T04:10:06.306Z","updated_at":"2025-04-06T13:11:00.365Z","avatar_url":"https://github.com/sofastack.png","language":"Java","readme":"# sofa-common-tools\n\n![build](https://github.com/sofastack/sofa-common-tools/workflows/build/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/alipay/sofa-common-tools/badge.svg?branch=master)](https://coveralls.io/github/sofastack/sofa-common-tools?branch=master) \n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) \n[![maven](https://img.shields.io/github/release/alipay/sofa-common-tools.svg)](https://github.com/sofastack/sofa-common-tools/releases)\n\n`sofa-common-tools` is a common dependency of SOFAStack middleware, it provides:\n1. Separate log space for application and middleware\n2. SOFA thread \n \nThe audience of this library is middleware and SDK developer.\n\n**Note:** Since version 1.2.0, sofa-common-tools don't support JDK 1.6 anymore. \n\n## Background\n\nIn daily developing, Java logging usually consists of choosing a log facade (e.g., JCL and SLF4j) and log implementation (e.g., Log4j2 and logback).\nSay you are developing an application that uses a JAR which utilizes log4j2 for logging.\nIn such scenario, you cannot choose log implementation other than log4j2 (log implementation conflicts if you choose Logback).\nSome solutions available:\n1. The jar uses log facade instead log implementation but application developers still have to provide log configuration\n2. The jar initialize loggers and appenders programmatically (This works well in Multi-ClassLoader environment where middleware/SDK developers handle many repeated work)\n3. Application resort to same log implementation as the JAR and provide also log configuration\n\nNone of the above solutions is perfect, `sofa-common-tools` provides a Midas touch: middleware/SDK developers print logs using *only* facade and hand the right to select whichever log implementation to application developer.\nAt the mean time, middleware/SDK developers provide log configurations per log implementation.\n`sofa-common-tools` detects automatically the log implementation and initializes appenders and loggers for middleware/SDK.\nTo differentiate SDKs/middlewares, each jar has its own log context and log space identifiable via `SpaceID` in `sofa-common-tools`. \n\nSome notes:\n- `sofa-common-tools` only supports SLF4j facade currently\n\n## Quick Start\nSay you are developing an OCR SDK for downstream to integrate. First, you choose `com.alipay.sdk.ocr` as your log space.\nSecond, define a logger factory to retrieve all the loggers you need:\n\n```java\nimport org.slf4j.Logger;\nimport com.alipay.sofa.common.log.LoggerSpaceManager;\n\npublic class AlipayOcrLoggerFactory {\n    private static final String OCR_LOGGER_SPACE = \"com.alipay.sdk.ocr\";\n\n    public static Logger getLogger(String name) {\n        if (name == null || name.isEmpty()) {\n            return null;\n        }\n\n        return LoggerSpaceManager.getLoggerBySpace(name, OCR_LOGGER_SPACE);\n    }\n\n    public static Logger getLogger(Class\u003c?\u003e klass) {\n        if (klass == null) {\n            return null;\n        }\n\n        return getLogger(klass.getCanonicalName());\n    }\n}\n```\n\nThird, create log configuration for your log space in classpath (space name `com.alipay.sdk.ocr` maps to `com/alipay/sdk/ocr/log/` ), for example\n```\n$ cd com/alipay/sdk/ocr/log \u0026\u0026 tree\n.\n├── log4j\n│   └── log-conf.xml\n├── log4j2\n│   └── log-conf.xml\n└── logback\n    └── log-conf.xml\n```\n\nThe directory name is quite self-evident. If application choose a log implementation you don't configure, error will be thrown.\n\nA sample configuration for logback `logback/log-conf.xml`:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cconfiguration\u003e\n    \u003cappender name=\"stdout\" class=\"ch.qos.logback.core.ConsoleAppender\"\u003e\n        \u003cencoder charset=\"UTF-8\"\u003e\n            \u003cpattern\u003e%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n\u003c/pattern\u003e\n        \u003c/encoder\u003e\n    \u003c/appender\u003e\n\n    \u003clogger name=\"com.alipay.foo\" level=\"INFO\" additivity=\"false\"\u003e\n        \u003cappender-ref ref=\"stdout\"/\u003e\n    \u003c/logger\u003e\n\n    \u003croot level=\"INFO\"\u003e\n        \u003cappender-ref ref=\"stdout\"/\u003e\n    \u003c/root\u003e\n\u003c/configuration\u003e\n```\n\nLastly, just logging\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Logger ocrLogger = AlipayOcrLoggerFactory.getLogger(\"com.alipay.foo\");\n        ocrLogger.info(\"hello world\");\n    }\n}\n```\n\nIn console, the following log will be printed:\n```\n17:42:41.083 [main] INFO com.alipay.foo - hello world\n```\n\n## Configuration\nThe configuration of corresponding logging implementation can be parameterized, that is to say, placeholders are allowed in XML file.\nBy default, `sofa-common-tools` provides following parameters with sensible default values:\n\n|Parameter|Default value|\n|---|---|\n|logging.path| ${user.home} |\n|file.encoding|UTF-8 |\n|logging.level.{spaceName}| INFO |\n|logging.path.{spaceName}|${logging.path}|\n\nApplication is able to override the value through JVM options, e.g., `-Dlogging.path=/home/admin`.\n\n### Customized Parameter\nMiddlewares/SDKs can defined customized parameters for xml placeholders as well.\nThose parameters must be initialized before using:\n```java\nimport org.slf4j.Logger;\nimport com.alipay.sofa.common.log.LoggerSpaceManager;import java.util.HashMap;\n\npublic class AlipayOcrLoggerFactory {\n    private static final String OCR_LOGGER_SPACE = \"com.alipay.sdk.ocr\";\n\n    static {\n        // Note: this step is important, as in Ark environment your SDK may be used in module dependency\n        // and will be initialized multiple times.\n        if (!MultiAppLoggerSpaceManager.isSpaceInitialized(OCR_LOGGER_SPACE)) {\n            Map spaceIdProperties = new HashMap\u003cString, String\u003e();\n            // Initialize your parameters here\n            MultiAppLoggerSpaceManager.init(OCR_LOGGER_SPACE, spaceIdProperties);\n        }\n    }\n\n    public static Logger getLogger(String name) {\n        if (name == null || name.isEmpty()) {\n            return null;\n        }\n\n        return LoggerSpaceManager.getLoggerBySpace(name, OCR_LOGGER_SPACE);\n    }\n\n    public static Logger getLogger(Class\u003c?\u003e klass) {\n        if (klass == null) {\n            return null;\n        }\n\n        return getLogger(klass.getCanonicalName());\n    }\n}\n```\n\n### Debugging\n1. The logging ability can be disabled totally through `sofa.middleware.log.disable` JVM option (Of course for middleware/SDK jar using `sofa-common-tools`).\n2. Debugging with specific log implementation, lock-down of other log implementation, e.g., `-Dlogback.middleware.log.disable=true` disables logback. All supported switch:\n    - log4j.middleware.log.disable\n    - log4j2.middleware.log.disable\n    - logback.middleware.log.disable\n\n### Miscellaneous\n- sofa.middleware.log.disable, defaults to `false`\n- logback.middleware.log.disable, defaults to `false`\n- log4j2.middleware.log.disable, defaults to `false`\n- log4j.middleware.log.disable, defaults to `false`\n\n#### LogLog\n`sofa-common-tools` uses internally `System.out` for logging, logging level can be set via JVM option `sofa.middleware.log.internal.level`.\n\n#### Console logging\n- Global configuration\n    - Switch `sofa.middleware.log.console` toggles console logging for all middleware/SDK, defaults to `false`\n    - `sofa.middleware.log.console.level` configures log level globally\n- Independent middleware/SDK configuration\n    + Switch `sofa.middleware.log.${spaceid}.console` toggles console logging for corresponding middleware/SDK, defaults to `false`\n    + `sofa.middleware.log.{space id}.console.level` configures log level correspondingly, which overrides global log level  \n\n##### Logging pattern\n+ logback: `sofa.middleware.log.console.logback.pattern` defaults to `%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } --- [%15.15t] %-40.40logger{39} : %m%n`\n+ log4j2: `sofa.middleware.log.console.log4j2.pattern` defaults to `%d{yyyy-MM-dd HH:mm:ss.SSS} %5p %X{PID} --- [%15.15t] %-40.40logger{39} : %m%n`\n\nConsole logging options can be passed through JVM option or Spring Boot `properties`.\n\n## Compiling\nMaven 3.2.5+, JDK Version 1.6+\n\n## LICENSE\n\n[Apache 2.0](./LICENSE)\n\n## Contribution\n\n[Contribution Guide](./CONTRIBUTING.md)\n\n\n\n\n\n","funding_links":[],"categories":["工具库"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsofastack%2Fsofa-common-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsofastack%2Fsofa-common-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsofastack%2Fsofa-common-tools/lists"}