{"id":13482641,"url":"https://github.com/elvishew/xLog","last_synced_at":"2025-03-27T13:32:22.056Z","repository":{"id":37731335,"uuid":"48155157","full_name":"elvishew/xLog","owner":"elvishew","description":"Android logger, pretty, powerful and flexible, log to everywhere, save to file, all you want is here.","archived":false,"fork":false,"pushed_at":"2024-07-28T16:47:45.000Z","size":1616,"stargazers_count":3218,"open_issues_count":63,"forks_count":429,"subscribers_count":59,"default_branch":"master","last_synced_at":"2025-03-26T09:01:40.226Z","etag":null,"topics":["android","android-log","backup","clean","file","filter","json","log","logcat","logger","save","xlog","xml"],"latest_commit_sha":null,"homepage":"","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/elvishew.png","metadata":{"files":{"readme":"README.md","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":"2015-12-17T05:50:05.000Z","updated_at":"2025-03-25T01:25:34.000Z","dependencies_parsed_at":"2024-01-13T18:24:36.849Z","dependency_job_id":"9f2020bb-7833-4e9d-b30f-55f9c01af08d","html_url":"https://github.com/elvishew/xLog","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elvishew%2FxLog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elvishew%2FxLog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elvishew%2FxLog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elvishew%2FxLog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elvishew","download_url":"https://codeload.github.com/elvishew/xLog/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245854580,"owners_count":20683379,"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":["android","android-log","backup","clean","file","filter","json","log","logcat","logger","save","xlog","xml"],"created_at":"2024-07-31T17:01:04.011Z","updated_at":"2025-03-27T13:32:22.030Z","avatar_url":"https://github.com/elvishew.png","language":"Java","readme":"# XLog\n\n![](https://travis-ci.org/elvishew/xLog.svg?branch=master)\n\n[简体中文](https://github.com/elvishew/xLog/blob/master/README_ZH.md)\n\nLightweight and pretty, powerful and flexible logger for android and java, can print the log to Logcat, Console and Files, or anywhere if you like.\n\n## Logcat Output\n\n![](https://github.com/elvishew/XLog/blob/master/images/logcat-output.png)\n\n## Quick Start\n\nDependency\n\n```groovy\nimplementation 'com.elvishew:xlog:1.11.1'\n```\n\nInitialization\n\n```java\nXLog.init(LogLevel.ALL);\n```\n\nLogging\n\n```java\nXLog.d(\"hello xlog\");\n```\n\n## Logging\n\nLog simple message.\n\n```java\nXLog.d(message);\n```\n\nLog a message with throwable, usually use when exception is thrown.\n\n```java\nXLog.e(message, throwable);\n```\n\nFormat string is also supported, so you don't have to append so many strings and variables by `+`.\n\n```java\nXLog.d(\"Hello %s, I am %d\", \"Elvis\", 20);\n```\n\nUnformatted JSON and XML string will be formatted automatically.\n\n```java\nXLog.json(JSON_CONTENT);\nXLog.xml(XML_CONTENT);\n```\n\nAll `Collection`s and `Map`s data are supported.\n\n```java\nXLog.d(array);\nXLog.d(list);\nXLog.d(map);\n```\n\nIf needed, you can also dump `Intent` and `Bundle` object directly.\n\n```java\nXLog.d(intent);\nXLog.d(bundle);\n```\n\nIn fact, you can dump any type of object if you want. You can specify an `ObjectFormatter` for specific type, otherwise `toString()` will be used when converting the object to a string.\n\n```java\nXLog.d(object);\n```\n\nNote: `v/d/i/w/e` are optional, `v` for `VERBOSE`, `d` for `DEBUG`, `i` for `INFO`, `w` for `WARNING` and `e` for `ERROR`.\n\n## Config\n\n`xLog` is very flexible, almost every component is configurable.\n\nWhen initialization, there are a simple way\n\n```java\nXLog.init(LogLevel.ALL);\n```\n\nand advance way.\n\n```java\nLogConfiguration config = new LogConfiguration.Builder()\n    .logLevel(BuildConfig.DEBUG ? LogLevel.ALL             // Specify log level, logs below this level won't be printed, default: LogLevel.ALL\n        : LogLevel.NONE)\n    .tag(\"MY_TAG\")                                         // Specify TAG, default: \"X-LOG\"\n    .enableThreadInfo()                                    // Enable thread info, disabled by default\n    .enableStackTrace(2)                                   // Enable stack trace info with depth 2, disabled by default\n    .enableBorder()                                        // Enable border, disabled by default\n    .jsonFormatter(new MyJsonFormatter())                  // Default: DefaultJsonFormatter\n    .xmlFormatter(new MyXmlFormatter())                    // Default: DefaultXmlFormatter\n    .throwableFormatter(new MyThrowableFormatter())        // Default: DefaultThrowableFormatter\n    .threadFormatter(new MyThreadFormatter())              // Default: DefaultThreadFormatter\n    .stackTraceFormatter(new MyStackTraceFormatter())      // Default: DefaultStackTraceFormatter\n    .borderFormatter(new MyBoardFormatter())               // Default: DefaultBorderFormatter\n    .addObjectFormatter(AnyClass.class,                    // Add formatter for specific class of object\n        new AnyClassObjectFormatter())                     // Use Object.toString() by default\n    .addInterceptor(new BlacklistTagsFilterInterceptor(    // Add blacklist tags filter\n        \"blacklist1\", \"blacklist2\", \"blacklist3\"))\n    .addInterceptor(new MyInterceptor())                   // Add other log interceptor\n    .build();\n\nPrinter androidPrinter = new AndroidPrinter(true);         // Printer that print the log using android.util.Log\nPrinter consolePrinter = new ConsolePrinter();             // Printer that print the log to console using System.out\nPrinter filePrinter = new FilePrinter                      // Printer that print(save) the log to file\n    .Builder(\"\u003cpath-to-logs-dir\u003e\")                         // Specify the directory path of log file(s)\n    .fileNameGenerator(new DateFileNameGenerator())        // Default: ChangelessFileNameGenerator(\"log\")\n    .backupStrategy(new NeverBackupStrategy())             // Default: FileSizeBackupStrategy(1024 * 1024)\n    .cleanStrategy(new FileLastModifiedCleanStrategy(MAX_TIME))     // Default: NeverCleanStrategy()\n    .flattener(new MyFlattener())                          // Default: DefaultFlattener\n    .writer(new MyWriter())                                // Default: SimpleWriter\n    .build();\n\nXLog.init(                                                 // Initialize XLog\n    config,                                                // Specify the log configuration, if not specified, will use new LogConfiguration.Builder().build()\n    androidPrinter,                                        // Specify printers, if no printer is specified, AndroidPrinter(for Android)/ConsolePrinter(for java) will be used.\n    consolePrinter,\n    filePrinter);\n```\n\nAfter initialization, a global `Logger` with the global config is created, all logging via `XLog` will pass to this global `Logger`.\n\nBesides, you can create unlimmited number of `Logger` with different configs:\n\n* Base on global `Logger`, change tag to `\"TAG-A\"`.\n\n```java\nLogger logger = XLog.tag(\"TAG-A\")\n                    ... // other overrides\n                    .build();\nlogger.d(\"Message with custom tag\");\n```\n\n* Base on global `Logger`, enable border and thread info.\n\n```java\nLogger logger = XLog.enableBorder()\n                    .enableThread()\n                    ... // other overrides\n                    .build();\nlogger.d(\"Message with thread info and border\");\n```\n\nyou can also log with one-time-use config:\n\n```java\nXLog.tag(\"TAG-A\").d(\"Message with custom tag\");\nXLog.enableBorder().enableThread().d(\"Message with thread info and border\");\n```\n\n## Print to anywhere\n\nWith one logging statement\n\n```java\nXLog.d(\"hello xlog\");\n```\nyou can print the `\"hello xlog\"` to\n\n* Logcat (with `AndroidPrinter`)\n\n* File (with `FilePrinter`)\n\nand anywhere you like.\n\nJust implement the `Printer` interface, and specify it when initializing\n\n```java\nXLog.init(config, printer1, printer2...printerN);\n```\n\nor when creating a non-global `Logger`\n\n```java\nLogger logger = XLog.printer(printer1, printer2...printerN)\n                    .build();\n```\n\nor when one-time-use logging\n\n```java\nXLog.printer(printer1, printer2...printerN).d(\"Message with one-time-use printers\");\n```\n\n## Save logs to file\n\nTo save logs to file, you need to create a `FilePrinter`\n\n```java\nPrinter filePrinter = new FilePrinter                      // Printer that print(save) the log to file\n    .Builder(\"\u003cpath-to-logs-dir\u003e\")                         // Specify the directory path of log file(s)\n    .fileNameGenerator(new DateFileNameGenerator())        // Default: ChangelessFileNameGenerator(\"log\")\n    .backupStrategy(new NeverBackupStrategy())             // Default: FileSizeBackupStrategy(1024 * 1024)\n    .cleanStrategy(new FileLastModifiedCleanStrategy(MAX_TIME))     // Default: NeverCleanStrategy()\n    .flattener(new MyFlattener())                          // Default: DefaultFlattener\n    .build();\n```\n\nand add the `FilePrinter` to XLog when initializing\n\n```java\nXLog.init(config, filePrinter);\n```\n\nor when creating an non-global `Logger`\n\n```java\nLogger logger = XLog.printer(filePrinter)\n                    ... // other overrides\n                    .build();\n```\n\nor when one-time-use logging\n\n```java\nXLog.printer(filePrinter).d(\"Message with one-time-use printers\");\n```\n\n### Save third party logs\n\nYou can config `LibCat` after initializing `XLog`.\n\n```java\nLibCat.config(true, filePrinter);\n```\n\nThen, the logs logged by third party modules/libraries(within same app) will be saved to file too.\n\nGo to [LibCat] for more details.\n\n### Custom file name\n\nYou can specify the file name directly, or categorize the logs to different files by some rules.\n\n* Use `ChangelessFileNameGenerator`, you can specify a changeless file name.\n\n```\nlogs-dir\n└──log\n```\n\n* Use `LevelFileNameGenerator`, it will categorize logs by levels automatically.\n\n```\nlogs-dir\n├──VERBOSE\n├──DEBUG\n├──INFO\n├──WARN\n└──ERROR\n```\n\n* Use `DateFileNameGenerator`, it will categorize logs by date automatically.\n\n```\nlogs-dir\n├──2020-01-01\n├──2020-01-02\n├──2020-01-03\n└──2020-01-04\n```\n\n* Implement `FileNameGenerator` directly, make the file name generating rules by yourself.\n\n```\nlogs-dir\n├──2020-01-01-\u003chash1\u003e.log\n├──2020-01-01-\u003chash2\u003e.log\n├──2020-01-03-\u003chash\u003e.log\n└──2020-01-05-\u003chash\u003e.log\n```\n\nBy default, a `ChangelessFileNameGenerator` with log file name `log` is used.\n\n\n### Custom log format\n\nLog elements(date, time, level and message) should be flattened to a single string before being printed to the file, you need a `Flattener` to do that.\n\nWe have defined a `PatternFlattener`, which may satisfy most of you. All you need to do is just passing a pattern with parameters to the flattener.\n\nSupported parameters:\n\n|Parameter|Represents|\n|:---:|---|\n|{d}|Date in default date format \"yyyy-MM-dd HH:mm:ss.SSS\"|\n|{d format}|Date in specific date format|\n|{l}|Short name of log level. e.g: V/D/I|\n|{L}|Long name of log level. e.g: VERBOSE/DEBUG/INFO|\n|{t}|Tag of log|\n|{m}|Message of log|\n\nImagine there is a log, with `DEBUG` level, `\"my_tag\"` tag and `\"Simple message\"` message, the flattened log would be as below.\n\n|Pattern|Flattened log|\n|:---:|---|\n|{d} {l}/{t}: {m}|2016-11-30 13:00:00.000 D/my_tag: Simple message|\n|{d yyyy-MM-dd HH:mm:ss.SSS} {l}/{t}: {m}|2016-11-30 13:00:00.000 D/my_tag: Simple message|\n|{d yyyy/MM/dd HH:mm:ss} {l}\\|{t}: {m}|2016/11/30 13:00:00 D\\|my_tag: Simple message|\n|{d yy/MM/dd HH:mm:ss} {l}\\|{t}: {m}|16/11/30 13:00:00 D\\|my_tag: Simple message|\n|{d MM/dd HH:mm} {l}-{t}-{m}|11/30 13:00 D-my_tag-Simple message|\n\nIf you don't even want to construct a pattern, `ClassicFlattener` is for you. It is a `PatternFlattener` with a default pattern `{d} {l}/{t}: {m}`.\n\nBy default, `FilePrinter` use a `DefaultFlattener`, which just simply concat the timestamp and message together. You may don't like it, so please remember to specify your own `Flattener`, maybe a `ClassicFlattener`.\n\n### Auto backup\n\nEvery single log file may grow to an unexpected size, a `AbstractBackupStrategy2` allow you to start a new file at some point, and change the old file name with `.bak.n`(n is the backup index) suffix.\n\n```\nlogs-dir\n├──log\n├──log.bak.1\n├──log.bak.2\n├──log.bak.3\n├──...\n└──log.bak.n\n```\n\nIf you don't like the `.bak.n` suffix, you can use `BackupStrategy2` directly to specify the backup file name.\n\nMostly, you just want to start a new file when the log file reach a specified max-size, so `FileSizeBackupStrategy2` is presented for you.\n\nBy default, `FileSizeBackupStrategy(1024*1024)` is used, which will auto backup the log file when it reach a size of 1M. Besides, there will only be one logging file and one backup file in the same time, that means you can save at most only 2M logs.\n\nSo, if you want to save more logs, and more backup files, please use `FileSizeBackupStrategy2` instead, this allow you keeping multiple backup files in the same time.\n\n### Auto clean\n\nIf you use a changeable `FileNameGenerator`, there would be more than one log files in the logs folder, and gets more and more as time goes on. Besides, if you use a backup strategy not limiting the max backup index, that would also make numbers of log files out of control. To prevent running out of disk space, you need a `CleanStrategy`.\n\nTypically, you can use a `FileLastModifiedCleanStrategy`, which will delete log files that have not been modified for a period of time(e.g., a week) during initialization.\n\nBy default, `NeverCleanStrategy` is used, which will never do any cleaning.\n\n### Compress log files\n\nJust call\n\n```java\nLogUtil.compress(\"\u003cpath-to-logs-dir\u003e\", \"\u003cpath-to-zip-file\u003e\");\n```\n\na zip file will be created and the entire log folder will be compressed and written to it, so you can easily collect the user logs for issue-debug.\n\nNote: the origianl log files will not be deleted.\n\n## Intercept and filter log\n\nBefore each log being printed, you have a chance to modify or filter out the log, by using an `Interceptor`.\n\nWe have already predefined some `Interceptor` for you, e.g. `WhitelistTagsFilterInterceptor` only allows the logs of specified tags to be printed, and `BlacklistTagsFilterInterceptor` is used to filter out(not print) logs of specified tags.\n\nYou can specify multiple `Interceptor`s for a single `Logger`, these `Interceptor`s will be given the opportunity to modify or filter out logs in the order in which they were added. Once a log is filtered out by an `Interceptor`, subsequent `Interceptor`s will no longer get this log.\n\n## Format object\n\nWhen logging an object\n\n```java\nXLog.d(object);\n```\n\nthe `toString` of the object will be called by default.\n\nSometimes, the `toString` implementation of the object is not quite what you want, so you need an `ObjectFormatter` to define how this type of object should be converted to a string when logging.\n\nOn the android platform, we predefine `IntentFormatter` and `BundleFormatter` for `Intent` and `Bundle` class.\n\nYou can implement and add your own `ObjectFormatter` for any class.\n\nPlease note, `ObjectFormatter`s only work when logging an object.\n\n## Similar libraries\n\n* [logger](https://github.com/orhanobut/logger)\n* [KLog](https://github.com/ZhaoKaiQiang/KLog)\n\nCompare with other logger libraries:\n\n* Well documented\n* So flexible that you can easily customize or enhance it\n\n## Compatibility\n\nIn order to be compatible with [Android Log], all the methods of [Android Log] are supported here.\n\nSee the Log class defined in [XLog].\n\n```java\nLog.v(String, String);\nLog.v(String, String, Throwable);\nLog.d(String, String);\nLog.d(String, String, Throwable);\nLog.i(String, String);\nLog.i(String, String, Throwable);\nLog.w(String, String);\nLog.w(String, String, Throwable);\nLog.wtf(String, String);\nLog.wtf(String, String, Throwable);\nLog.e(String, String);\nLog.e(String, String, Throwable);\nLog.println(int, String, String);\nLog.isLoggable(String, int);\nLog.getStackTraceString(Throwable);\n```\n\n### Migration\n\nIf you have a big project using the [Android Log], and it is a hard work to change all usage of [Android Log] to [XLog], then you can use the compatible API, simply replace all 'android.util.Log' to 'com.elvishew.xlog.XLog.Log'.  \n(**For a better performance, you should think about not using the compatible API.**)\n\n#### Linux/Cygwin\n\n```shell\ngrep -rl \"android.util.Log\" \u003cyour-source-directory\u003e | xargs sed -i \"s/android.util.Log/com.elvishew.xlog.XLog.Log/g\"\n```\n\n#### Mac\n\n```shell\ngrep -rl \"android.util.Log\" \u003cyour-source-directory\u003e | xargs sed -i \"\" \"s/android.util.Log/com.elvishew.xlog.XLog.Log/g\"\n```\n\n#### Android Studio\n\n1. In 'Project' pane, switch to the 'Project Files' tab, then right-click on the your source directory.\n2. In the menu, click the 'Replace in Path...' option.\n3. In the dialog, fill the 'Text to find' with 'android.util.Log', and 'Replace with' with 'com.elvishew.xlog.XLog.Log', and click 'Find'.\n\nOptionally, instead of replacing all 'android.util.Log', you can just use [LibCat] to intercept all logs logged by `android.util.Log` and redirect them to `XLog`'s `Printer`.\n\n## [Issues](https://github.com/elvishew/xLog/issues)\n\nIf you meet any problem when using XLog, or have any suggestion, please feel free to create an issue.  \nBefore creating an issue, please check if there is an existed one.\n\n## Thanks\n\nThanks to [Orhan Obut](https://github.com/orhanobut)'s [logger](https://github.com/orhanobut/logger), it give us many ideas of what a logger can do.\n\nThanks to [Serge Zaitsev](https://github.com/zserge)'s [log](https://github.com/zserge/log), it give us the thought of making `xLog` compatible with [Android Log].\n\n## License\n\n\u003cpre\u003e\nCopyright 2015-2021 Elvis Hew\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\u003c/pre\u003e\n\n[Android Log]: http://developer.android.com/reference/android/util/Log.html\n[XLog]: https://github.com/elvishew/xLog/blob/master/xlog/src/main/java/com/elvishew/xlog/XLog.java\n[Logger]: https://github.com/elvishew/xLog/blob/master/xlog/src/main/java/com/elvishew/xlog/Logger.java\n[LibCat]: https://github.com/elvishew/xLog/blob/master/xlog-libcat/README.md\n","funding_links":[],"categories":["Java","日志库"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felvishew%2FxLog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felvishew%2FxLog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felvishew%2FxLog/lists"}