GithubHelp home page GithubHelp logo

elvishew / xlog Goto Github PK

View Code? Open in Web Editor NEW
3.1K 3.1K 414.0 1.58 MB

Android logger, pretty, powerful and flexible, log to everywhere, save to file, all you want is here.

License: Apache License 2.0

Java 99.71% Shell 0.29%
android android-log backup clean file filter json log logcat logger save xlog xml

xlog's Introduction

XLog

简体中文

Lightweight and pretty, powerful and flexible logger for android and java, can print the log to Logcat, Console and Files, or anywhere if you like.

Logcat Output

Quick Start

Dependency

implementation 'com.elvishew:xlog:1.11.1'

Initialization

XLog.init(LogLevel.ALL);

Logging

XLog.d("hello xlog");

Logging

Log simple message.

XLog.d(message);

Log a message with throwable, usually use when exception is thrown.

XLog.e(message, throwable);

Format string is also supported, so you don't have to append so many strings and variables by +.

XLog.d("Hello %s, I am %d", "Elvis", 20);

Unformatted JSON and XML string will be formatted automatically.

XLog.json(JSON_CONTENT);
XLog.xml(XML_CONTENT);

All Collections and Maps data are supported.

XLog.d(array);
XLog.d(list);
XLog.d(map);

If needed, you can also dump Intent and Bundle object directly.

XLog.d(intent);
XLog.d(bundle);

In 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.

XLog.d(object);

Note: v/d/i/w/e are optional, v for VERBOSE, d for DEBUG, i for INFO, w for WARNING and e for ERROR.

Config

xLog is very flexible, almost every component is configurable.

When initialization, there are a simple way

XLog.init(LogLevel.ALL);

and advance way.

LogConfiguration config = new LogConfiguration.Builder()
    .logLevel(BuildConfig.DEBUG ? LogLevel.ALL             // Specify log level, logs below this level won't be printed, default: LogLevel.ALL
        : LogLevel.NONE)
    .tag("MY_TAG")                                         // Specify TAG, default: "X-LOG"
    .enableThreadInfo()                                    // Enable thread info, disabled by default
    .enableStackTrace(2)                                   // Enable stack trace info with depth 2, disabled by default
    .enableBorder()                                        // Enable border, disabled by default
    .jsonFormatter(new MyJsonFormatter())                  // Default: DefaultJsonFormatter
    .xmlFormatter(new MyXmlFormatter())                    // Default: DefaultXmlFormatter
    .throwableFormatter(new MyThrowableFormatter())        // Default: DefaultThrowableFormatter
    .threadFormatter(new MyThreadFormatter())              // Default: DefaultThreadFormatter
    .stackTraceFormatter(new MyStackTraceFormatter())      // Default: DefaultStackTraceFormatter
    .borderFormatter(new MyBoardFormatter())               // Default: DefaultBorderFormatter
    .addObjectFormatter(AnyClass.class,                    // Add formatter for specific class of object
        new AnyClassObjectFormatter())                     // Use Object.toString() by default
    .addInterceptor(new BlacklistTagsFilterInterceptor(    // Add blacklist tags filter
        "blacklist1", "blacklist2", "blacklist3"))
    .addInterceptor(new MyInterceptor())                   // Add other log interceptor
    .build();

Printer androidPrinter = new AndroidPrinter(true);         // Printer that print the log using android.util.Log
Printer consolePrinter = new ConsolePrinter();             // Printer that print the log to console using System.out
Printer filePrinter = new FilePrinter                      // Printer that print(save) the log to file
    .Builder("<path-to-logs-dir>")                         // Specify the directory path of log file(s)
    .fileNameGenerator(new DateFileNameGenerator())        // Default: ChangelessFileNameGenerator("log")
    .backupStrategy(new NeverBackupStrategy())             // Default: FileSizeBackupStrategy(1024 * 1024)
    .cleanStrategy(new FileLastModifiedCleanStrategy(MAX_TIME))     // Default: NeverCleanStrategy()
    .flattener(new MyFlattener())                          // Default: DefaultFlattener
    .writer(new MyWriter())                                // Default: SimpleWriter
    .build();

XLog.init(                                                 // Initialize XLog
    config,                                                // Specify the log configuration, if not specified, will use new LogConfiguration.Builder().build()
    androidPrinter,                                        // Specify printers, if no printer is specified, AndroidPrinter(for Android)/ConsolePrinter(for java) will be used.
    consolePrinter,
    filePrinter);

After initialization, a global Logger with the global config is created, all logging via XLog will pass to this global Logger.

Besides, you can create unlimmited number of Logger with different configs:

  • Base on global Logger, change tag to "TAG-A".
Logger logger = XLog.tag("TAG-A")
                    ... // other overrides
                    .build();
logger.d("Message with custom tag");
  • Base on global Logger, enable border and thread info.
Logger logger = XLog.enableBorder()
                    .enableThread()
                    ... // other overrides
                    .build();
logger.d("Message with thread info and border");

you can also log with one-time-use config:

XLog.tag("TAG-A").d("Message with custom tag");
XLog.enableBorder().enableThread().d("Message with thread info and border");

Print to anywhere

With one logging statement

XLog.d("hello xlog");

you can print the "hello xlog" to

  • Logcat (with AndroidPrinter)

  • File (with FilePrinter)

and anywhere you like.

Just implement the Printer interface, and specify it when initializing

XLog.init(config, printer1, printer2...printerN);

or when creating a non-global Logger

Logger logger = XLog.printer(printer1, printer2...printerN)
                    .build();

or when one-time-use logging

XLog.printer(printer1, printer2...printerN).d("Message with one-time-use printers");

Save logs to file

To save logs to file, you need to create a FilePrinter

Printer filePrinter = new FilePrinter                      // Printer that print(save) the log to file
    .Builder("<path-to-logs-dir>")                         // Specify the directory path of log file(s)
    .fileNameGenerator(new DateFileNameGenerator())        // Default: ChangelessFileNameGenerator("log")
    .backupStrategy(new NeverBackupStrategy())             // Default: FileSizeBackupStrategy(1024 * 1024)
    .cleanStrategy(new FileLastModifiedCleanStrategy(MAX_TIME))     // Default: NeverCleanStrategy()
    .flattener(new MyFlattener())                          // Default: DefaultFlattener
    .build();

and add the FilePrinter to XLog when initializing

XLog.init(config, filePrinter);

or when creating an non-global Logger

Logger logger = XLog.printer(filePrinter)
                    ... // other overrides
                    .build();

or when one-time-use logging

XLog.printer(filePrinter).d("Message with one-time-use printers");

Save third party logs

You can config LibCat after initializing XLog.

LibCat.config(true, filePrinter);

Then, the logs logged by third party modules/libraries(within same app) will be saved to file too.

Go to LibCat for more details.

Custom file name

You can specify the file name directly, or categorize the logs to different files by some rules.

  • Use ChangelessFileNameGenerator, you can specify a changeless file name.
logs-dir
└──log
  • Use LevelFileNameGenerator, it will categorize logs by levels automatically.
logs-dir
├──VERBOSE
├──DEBUG
├──INFO
├──WARN
└──ERROR
  • Use DateFileNameGenerator, it will categorize logs by date automatically.
logs-dir
├──2020-01-01
├──2020-01-02
├──2020-01-03
└──2020-01-04
  • Implement FileNameGenerator directly, make the file name generating rules by yourself.
logs-dir
├──2020-01-01-<hash1>.log
├──2020-01-01-<hash2>.log
├──2020-01-03-<hash>.log
└──2020-01-05-<hash>.log

By default, a ChangelessFileNameGenerator with log file name log is used.

Custom log format

Log 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.

We 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.

Supported parameters:

Parameter Represents
{d} Date in default date format "yyyy-MM-dd HH:mm:ss.SSS"
{d format} Date in specific date format
{l} Short name of log level. e.g: V/D/I
{L} Long name of log level. e.g: VERBOSE/DEBUG/INFO
{t} Tag of log
{m} Message of log

Imagine there is a log, with DEBUG level, "my_tag" tag and "Simple message" message, the flattened log would be as below.

Pattern Flattened log
{d} {l}/{t}: {m} 2016-11-30 13:00:00.000 D/my_tag: Simple message
{d yyyy-MM-dd HH:mm:ss.SSS} {l}/{t}: {m} 2016-11-30 13:00:00.000 D/my_tag: Simple message
{d yyyy/MM/dd HH:mm:ss} {l}|{t}: {m} 2016/11/30 13:00:00 D|my_tag: Simple message
{d yy/MM/dd HH:mm:ss} {l}|{t}: {m} 16/11/30 13:00:00 D|my_tag: Simple message
{d MM/dd HH:mm} {l}-{t}-{m} 11/30 13:00 D-my_tag-Simple message

If 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}.

By 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.

Auto backup

Every 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.

logs-dir
├──log
├──log.bak.1
├──log.bak.2
├──log.bak.3
├──...
└──log.bak.n

If you don't like the .bak.n suffix, you can use BackupStrategy2 directly to specify the backup file name.

Mostly, you just want to start a new file when the log file reach a specified max-size, so FileSizeBackupStrategy2 is presented for you.

By 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.

So, 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.

Auto clean

If 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.

Typically, 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.

By default, NeverCleanStrategy is used, which will never do any cleaning.

Compress log files

Just call

LogUtil.compress("<path-to-logs-dir>", "<path-to-zip-file>");

a 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.

Note: the origianl log files will not be deleted.

Intercept and filter log

Before each log being printed, you have a chance to modify or filter out the log, by using an Interceptor.

We 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.

You can specify multiple Interceptors for a single Logger, these Interceptors 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 Interceptors will no longer get this log.

Format object

When logging an object

XLog.d(object);

the toString of the object will be called by default.

Sometimes, 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.

On the android platform, we predefine IntentFormatter and BundleFormatter for Intent and Bundle class.

You can implement and add your own ObjectFormatter for any class.

Please note, ObjectFormatters only work when logging an object.

Similar libraries

Compare with other logger libraries:

  • Well documented
  • So flexible that you can easily customize or enhance it

Compatibility

In order to be compatible with Android Log, all the methods of Android Log are supported here.

See the Log class defined in XLog.

Log.v(String, String);
Log.v(String, String, Throwable);
Log.d(String, String);
Log.d(String, String, Throwable);
Log.i(String, String);
Log.i(String, String, Throwable);
Log.w(String, String);
Log.w(String, String, Throwable);
Log.wtf(String, String);
Log.wtf(String, String, Throwable);
Log.e(String, String);
Log.e(String, String, Throwable);
Log.println(int, String, String);
Log.isLoggable(String, int);
Log.getStackTraceString(Throwable);

Migration

If 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'.
(For a better performance, you should think about not using the compatible API.)

Linux/Cygwin

grep -rl "android.util.Log" <your-source-directory> | xargs sed -i "s/android.util.Log/com.elvishew.xlog.XLog.Log/g"

Mac

grep -rl "android.util.Log" <your-source-directory> | xargs sed -i "" "s/android.util.Log/com.elvishew.xlog.XLog.Log/g"

Android Studio

  1. In 'Project' pane, switch to the 'Project Files' tab, then right-click on the your source directory.
  2. In the menu, click the 'Replace in Path...' option.
  3. In the dialog, fill the 'Text to find' with 'android.util.Log', and 'Replace with' with 'com.elvishew.xlog.XLog.Log', and click 'Find'.

Optionally, 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.

If you meet any problem when using XLog, or have any suggestion, please feel free to create an issue.
Before creating an issue, please check if there is an existed one.

Thanks

Thanks to Orhan Obut's logger, it give us many ideas of what a logger can do.

Thanks to Serge Zaitsev's log, it give us the thought of making xLog compatible with Android Log.

License

Copyright 2015-2021 Elvis Hew

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

xlog's People

Contributors

elvishew avatar williamwue avatar wkingluoye avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xlog's Issues

日志格式有点别扭

老哥, 你好,
logcat打印的日志第一行的边框和和下面的没有对齐. 能否更改一下.
image

日志错位问题

Android studio 升级到3.1.4出现日志错位问题,2.3.3没有问题。
image
image

Log is no longer show in my logcat , my device is HUAWEI BTV-W09

I just used XLOG in my project, it does not work on my pad , i have no idea about that , even logcat print no except about XLOG, but when i use Log.i(TAG,MSG) then i can get the MSG in my logcat, how can i fix that?
P.S. the HUAWEI BTV-W09 's sdk version is 25 (Android7.0)

Bug? When logging to file, the time is not formatted but just a timestamp value

1479185204301|W|MY_TAG|╔═══════════════════════════════════════════════════════════════════════════════════════════════════
║Thread: RxComputationScheduler-1
╟───────────────────────────────────────────────────────────────────────────────────────────────────
║	├ com.jp.rxjavademo.MainActivity$9.onNext(MainActivity.java:236)
║	├ com.jp.rxjavademo.MainActivity$9.onNext(MainActivity.java:223)
║	├ rx.internal.util.ObserverSubscriber.onNext(ObserverSubscriber.java:34)
║	└ rx.observers.SafeSubscriber.onNext(SafeSubscriber.java:134)
╟───────────────────────────────────────────────────────────────────────────────────────────────────
║combineLatest: 177
╚═══════════════════════════════════════════════════════════════════════════════════════════════════

Cannot print anything

Gradle:2.2.2
Debug build

I compiled this library in my project's library module.
And init it in my application by XLog.init(BuildConfig.DEBUG ? LogLevel.ALL : LogLevel.NONE, new LogConfiguration.Builder().t().b().build());.
The library module is compiled by compile project(':library') in gradle file.My application is registered correctly in AndroidManifest.xml.
But it cannot print anything in activity when invoke XLog.d(msg);.
What's wrong?Thx.

Check if XLog already initialized

Hi,

Can you add the possibility to check whether the XLog has already been initialized?

When I run a bunch of Robolectric tests the following exception is being thrown:

java.lang.RuntimeException: java.lang.IllegalStateException: XLog is already initialized, do not initialize again

I am initializing the XLog in my application subclass:

 override fun onCreate() {
        super.onCreate()

        XLog.init(if (BuildConfig.DEBUG) LogLevel.ALL else LogLevel.NONE)
 }

It seems that Robolectric creates the application multiple times but XLog for some reason stays initialized.

What do you think? Maybe the public getter of sIsInitialized would be enough to solve this issue?

Pretty TimeStamp

Is there any way to change default timestamp from epoch to date string
1486381070403|D|X-LOG|Simple message
to
Mon, 06 Feb 2017 11:37:50.403 GMT|D|X-LOG|Simple message

动态的设置TAG

在不同的类里面设置不用的TAG,不想使用局部的用法,每次设置很多参数太麻烦,怎样实现动态设置TAG

在AS 3.0 上点击日志无法跳转

在AS 3.0 输出的日志不能点击跳转

代码配置:

XLog.init(new LogConfiguration.Builder()
                 .logLevel(BuildConfig.DEBUG ? LogLevel.ALL : LogLevel.NONE)
                .st(2)
                .b()
                .build());

日志如下:
image

How to log to internal storage?

Hi,
I need help with writing log files to device internal storage. How do we do that with xlog? Any help will be appreciated. Thanks in advance.

how can I change log level after initiation?

I initialize XLog in my project by code:

XLog.init(new LogConfiguration.Builder()
                .logLevel(Config.isLogEnabled() ? LogLevel.ALL : LogLevel.NONE)
                .t()
                .st(3)
                .b()
                .build());

The log level is set to LogLevel.NONE in release version, but I have a secret log switch to debug something, so, how can I change log level after XLog initialized?

Parse JSON error

I init your xLog in the application onCreate() with XLog.init(LogLevel.ALL);, but when I run my project it fail to print json string, only give me this error com.elvishew.xlog.formatter.FormatException: Parse JSON error. It's works well using android.util.Log to print the json string, don't know anything wrong, any help?

如何获取 sIsInitialized 变量?

up主,你好,我在初始化XLog的时候,设置了一个filePrinter,文件路径是通过一个封装过的工具类:StorageUtil获取的,获取这个路径的时候,做了一个“是否要创建目录”的判断,同时输出相关日志,此时由于XLog并未初始化,导致崩溃,所以,想手工判断一下是否初始化,否则不用XLog输出。

PS: XLog暂时用做日志文件备份,项目中还是有一个日志工具的,只不过在那个日志工具调用Log.x()后,再调用XLog

some confusion about filePrinter

The xLog is very powerful and pretty, i am excited in using it.
but when i use the function of printing log to the sdcrad, i meet some question.
for example,when i use a globalFilePrinter and a LocalFilePrinter in the same time,and set the file path same,and the filename generator by date as also, it would't create two log file, they will write in a same file. is it a BUG?
in another case, I just use a globalFilePrinter,then it will create one log file, does the xLog has the ability to clear the log file automatically ? If not ,the log file will be very large.

About stack trace info

Sometime I defined my L.java, and I use XLog in L.java.
L.java have some methods, example:

public static void e(String contents) {
    log(contents);
}

private static void log(String contents) {
    XLog.e(contents);
}

then I use L.java in MainActivity

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        L.e("Hello World");
}

I set st(3), and the log is :

├ com.whyalwaysmea.basemodule.L.log(L.java:156)
║ ├ com.whyalwaysmea.basemodule.L.e(L.java:127)
║ └ com.whyalwaysmea.diycode.MainActivity.onCreate(MainActivity.java:23)

Can I only see the last Info(MainActivity.java)? how to do it?
Thanks.

Customizable log levels

I'm looking for a way to customize log levels. E.g. we don't use verbose but we do use critical (higher than error). Currently all I can do is "transpose" the log levels with a wrapper and an interceptor or something making everything a mess (and stack traces incorrect because the wrapper is irrelevant).

How to print the thread info and the code line number

你好,请问怎样打印出线程与输出日志所在的代码行数,就像orhanobut的logger中那样。
如下面的:
Thread: main与MainActivity.initData (MainActivity.java:66)
╔═══════════════════════════════════════════
║ Thread: main
╟──────────────────────────────
║ MainActivity.initData (MainActivity.java:66)
╟──────────────────────────────
║ {
║ "name": "Elvis",
║ "age": 18
║ }
╚═══════════════════════════════════════════

how to encrypt logs

Hi,
First of all thanks for such a wonderful library.
How can i encrypt/decrypt logs using this library. I want to store and read logs from encrypted file, so that normal user can't read the logs. One way is to add them in (.Folder) but still a user can access the files

log backup

Hi,I know Xlog is great,but I incomprehension why there is a log backup function,If you can tell me It applies to which scenes?I will be very grateful.

无法打印json

String jsonString = "{"name": "Elvis", "age": 18}";
XLog.json(jsonString);

打印不出来..

delete logs

can auto delete logs by time or other ways

出错没有抛出异常吗?

我在application的onCreate()中初始化的XLog,不知道什么原因执行到这里有时候回卡死在这里,捕获异常也没有反应,我猜测是内部异常了但是没有抛出,导致卡死

Custome tag

Hi.
First of all I have to say this is a very perfect library, But I wish it support custom tag likes log.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.