/* * Copyright 2015 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. */ package com.elvishew.xlog; import android.app.Application; import com.elvishew.xlog.formatter.border.BorderFormatter; import com.elvishew.xlog.formatter.message.json.JsonFormatter; import com.elvishew.xlog.formatter.message.object.ObjectFormatter; import com.elvishew.xlog.formatter.message.throwable.ThrowableFormatter; import com.elvishew.xlog.formatter.message.xml.XmlFormatter; import com.elvishew.xlog.formatter.stacktrace.StackTraceFormatter; import com.elvishew.xlog.formatter.thread.ThreadFormatter; import com.elvishew.xlog.interceptor.Interceptor; import com.elvishew.xlog.internal.DefaultsFactory; import com.elvishew.xlog.internal.Platform; import com.elvishew.xlog.internal.util.StackTraceUtil; import com.elvishew.xlog.printer.Printer; import com.elvishew.xlog.printer.PrinterSet; /** * A log tool which can be used in android or java, the most important feature is it can print the * logs to multiple place in the same time, such as android shell, console and file, you can * even print the log to the remote server if you want, all of these can be done just within one * calling. * <br>Also, XLog is very flexible, almost every component is replaceable. * <p> * <b>How to use in a general way:</b> * <p> * <b>1. Initial the log system.</b> * <br>Using one of * <br>{@link XLog#init()} * <br>{@link XLog#init(int)}, * <br>{@link XLog#init(LogConfiguration)} * <br>{@link XLog#init(Printer...)}, * <br>{@link XLog#init(int, Printer...)}, * <br>{@link XLog#init(LogConfiguration, Printer...)}, * <br>that will setup a {@link Logger} for a global usage. * If you want to use a customized configuration instead of the global one to log something, you can * start a customization logging. * <p> * For android, a best place to do the initialization is {@link Application#onCreate()}. * <p> * <b>2. Start to log.</b> * <br>{@link #v(String, Object...)}, {@link #v(String)} and {@link #v(String, Throwable)} are for * logging a {@link LogLevel#INFO} message. * <br>{@link #d(String, Object...)}, {@link #d(String)} and {@link #d(String, Throwable)} are for * logging a {@link LogLevel#DEBUG} message. * <br>{@link #i(String, Object...)}, {@link #i(String)} and {@link #i(String, Throwable)} are for * logging a {@link LogLevel#INFO} message. * <br>{@link #w(String, Object...)}, {@link #w(String)} and {@link #w(String, Throwable)} are for * logging a {@link LogLevel#WARN} message. * <br>{@link #e(String, Object...)}, {@link #e(String)} and {@link #e(String, Throwable)} are for * logging a {@link LogLevel#ERROR} message. * <br>{@link #log(int, String, Object...)}, {@link #log(int, String)} and * {@link #log(int, String, Throwable)} are for logging a specific level message. * <br>{@link #json(String)} is for logging a {@link LogLevel#DEBUG} JSON string. * <br>{@link #xml(String)} is for logging a {@link LogLevel#DEBUG} XML string. * <br> Also, you can directly log any object with specific log level, like {@link #v(Object)}, * and any object array with specific log level, like {@link #v(Object[])}. * <p> * <b>How to use in a dynamically customizing way after initializing the log system:</b> * <p> * <b>1. Start a customization.</b> * <br>Call any of * <br>{@link #logLevel(int)} * <br>{@link #tag(String)}, * <br>{@link #t()}, * <br>{@link #nt()}, * <br>{@link #st(int)}, * <br>{@link #nst()}, * <br>{@link #b()}, * <br>{@link #nb()}, * <br>{@link #jsonFormatter(JsonFormatter)}, * <br>{@link #xmlFormatter(XmlFormatter)}, * <br>{@link #threadFormatter(ThreadFormatter)}, * <br>{@link #stackTraceFormatter(StackTraceFormatter)}, * <br>{@link #throwableFormatter(ThrowableFormatter)} * <br>{@link #borderFormatter(BorderFormatter)} * <br>{@link #addObjectFormatter(Class, ObjectFormatter)} * <br>{@link #addInterceptor(Interceptor)} * <br>{@link #printers(Printer...)}, * <br>it will return a {@link Logger.Builder} object. * <p> * <b>2. Finish the customization.</b> * <br>Continue to setup other fields of the returned {@link Logger.Builder}. * <p> * <b>3. Build a dynamically generated {@link Logger}.</b> * <br>Call the {@link Logger.Builder#build()} of the returned {@link Logger.Builder}. * <p> * <b>4. Start to log.</b> * <br>The logging methods of a {@link Logger} is completely same as that ones in {@link XLog}. * <br>As a convenience, you can ignore the step 3, just call the logging methods of * {@link Logger.Builder}, it will automatically build a {@link Logger} and call the target * logging method. * <p> * <b>Compatibility:</b> * <p> * In order to be compatible with {@link android.util.Log}, all the methods of * {@link android.util.Log} are supported here. * See: * <br>{@link Log#v(String, String)}, {@link Log#v(String, String, Throwable)} * <br>{@link Log#d(String, String)}, {@link Log#d(String, String, Throwable)} * <br>{@link Log#i(String, String)}, {@link Log#i(String, String, Throwable)} * <br>{@link Log#w(String, String)}, {@link Log#w(String, String, Throwable)} * <br>{@link Log#wtf(String, String)}, {@link Log#wtf(String, String, Throwable)} * <br>{@link Log#e(String, String)}, {@link Log#e(String, String, Throwable)} * <br>{@link Log#println(int, String, String)} * <br>{@link Log#isLoggable(String, int)} * <br>{@link Log#getStackTraceString(Throwable)} * <p> */ public class XLog { /** * Global logger for all direct logging via {@link XLog}. */ private static Logger sLogger; /** * Global log configuration. */ static LogConfiguration sLogConfiguration; /** * Global log printer. */ static Printer sPrinter; static boolean sIsInitialized; /** * Prevent instance. */ private XLog() { } /** * Initialize log system, should be called only once. * * @since 1.3.0 */ public static void init() { init(new LogConfiguration.Builder().build(), DefaultsFactory.createPrinter()); } /** * Initialize log system, should be called only once. * * @param logLevel the log level, logs with a lower level than which would not be printed */ public static void init(int logLevel) { init(new LogConfiguration.Builder().logLevel(logLevel).build(), DefaultsFactory.createPrinter()); } /** * Initialize log system, should be called only once. * * @param logLevel the log level, logs with a lower level than which would not be printed * @param logConfiguration the log configuration * @deprecated the log level is part of log configuration now, use {@link #init(LogConfiguration)} * instead, since 1.3.0 */ @Deprecated public static void init(int logLevel, LogConfiguration logConfiguration) { init(new LogConfiguration.Builder(logConfiguration).logLevel(logLevel).build()); } /** * Initialize log system, should be called only once. * * @param logConfiguration the log configuration * @since 1.3.0 */ public static void init(LogConfiguration logConfiguration) { init(logConfiguration, DefaultsFactory.createPrinter()); } /** * Initialize log system, should be called only once. * * @param printers the printers, each log would be printed by all of the printers * @since 1.3.0 */ public static void init(Printer... printers) { init(new LogConfiguration.Builder().build(), printers); } /** * Initialize log system, should be called only once. * * @param logLevel the log level, logs with a lower level than which would not be printed * @param printers the printers, each log would be printed by all of the printers */ public static void init(int logLevel, Printer... printers) { init(new LogConfiguration.Builder().logLevel(logLevel).build(), printers); } /** * Initialize log system, should be called only once. * * @param logLevel the log level, logs with a lower level than which would not be printed * @param logConfiguration the log configuration * @param printers the printers, each log would be printed by all of the printers * @deprecated the log level is part of log configuration now, * use {@link #init(LogConfiguration, Printer...)} instead, since 1.3.0 */ @Deprecated public static void init(int logLevel, LogConfiguration logConfiguration, Printer... printers) { init(new LogConfiguration.Builder(logConfiguration).logLevel(logLevel).build(), printers); } /** * Initialize log system, should be called only once. * * @param logConfiguration the log configuration * @param printers the printers, each log would be printed by all of the printers * @since 1.3.0 */ public static void init(LogConfiguration logConfiguration, Printer... printers) { if (sIsInitialized) { Platform.get().warn("XLog is already initialized, do not initialize again"); } sIsInitialized = true; if (logConfiguration == null) { throw new IllegalArgumentException("Please specify a LogConfiguration"); } sLogConfiguration = logConfiguration; sPrinter = new PrinterSet(printers); sLogger = new Logger(sLogConfiguration, sPrinter); } /** * Throw an IllegalStateException if not initialized. */ static void assertInitialization() { if (!sIsInitialized) { throw new IllegalStateException("Do you forget to initialize XLog?"); } } /** * Start to customize a {@link Logger} and set the log level. * * @param logLevel the log level to customize * @return the {@link Logger.Builder} to build the {@link Logger} * @since 1.3.0 */ public static Logger.Builder logLevel(int logLevel) { return new Logger.Builder().logLevel(logLevel); } /** * Start to customize a {@link Logger} and set the tag. * * @param tag the tag to customize * @return the {@link Logger.Builder} to build the {@link Logger} */ public static Logger.Builder tag(String tag) { return new Logger.Builder().tag(tag); } /** * Start to customize a {@link Logger} and enable thread info. * * @return the {@link Logger.Builder} to build the {@link Logger} */ public static Logger.Builder t() { return new Logger.Builder().t(); } /** * Start to customize a {@link Logger} and disable thread info. * * @return the {@link Logger.Builder} to build the {@link Logger} */ public static Logger.Builder nt() { return new Logger.Builder().nt(); } /** * Start to customize a {@link Logger} and enable stack trace. * * @param depth the number of stack trace elements we should log, 0 if no limitation * @return the {@link Logger.Builder} to build the {@link Logger} */ public static Logger.Builder st(int depth) { return new Logger.Builder().st(depth); } /** * Start to customize a {@link Logger} and enable stack trace. * * @param stackTraceOrigin the origin of stack trace elements from which we should NOT log, * it can be a package name like "com.elvishew.xlog", a class name * like "com.yourdomain.logWrapper", or something else between * package name and class name, like "com.yourdomain.". * It is mostly used when you are using a logger wrapper * @param depth the number of stack trace elements we should log, 0 if no limitation * @return the {@link Logger.Builder} to build the {@link Logger} * @since 1.4.0 */ public static Logger.Builder st(String stackTraceOrigin, int depth) { return new Logger.Builder().st(stackTraceOrigin, depth); } /** * Start to customize a {@link Logger} and disable stack trace. * * @return the {@link Logger.Builder} to build the {@link Logger} */ public static Logger.Builder nst() { return new Logger.Builder().nst(); } /** * Start to customize a {@link Logger} and enable border. * * @return the {@link Logger.Builder} to build the {@link Logger} */ public static Logger.Builder b() { return new Logger.Builder().b(); } /** * Start to customize a {@link Logger} and disable border. * * @return the {@link Logger.Builder} to build the {@link Logger} */ public static Logger.Builder nb() { return new Logger.Builder().nb(); } /** * Start to customize a {@link Logger} and set the {@link JsonFormatter}. * * @param jsonFormatter the {@link JsonFormatter} to customize * @return the {@link Logger.Builder} to build the {@link Logger} */ public static Logger.Builder jsonFormatter(JsonFormatter jsonFormatter) { return new Logger.Builder().jsonFormatter(jsonFormatter); } /** * Start to customize a {@link Logger} and set the {@link XmlFormatter}. * * @param xmlFormatter the {@link XmlFormatter} to customize * @return the {@link Logger.Builder} to build the {@link Logger} */ public static Logger.Builder xmlFormatter(XmlFormatter xmlFormatter) { return new Logger.Builder().xmlFormatter(xmlFormatter); } /** * Start to customize a {@link Logger} and set the {@link ThrowableFormatter}. * * @param throwableFormatter the {@link ThrowableFormatter} to customize * @return the {@link Logger.Builder} to build the {@link Logger} */ public static Logger.Builder throwableFormatter(ThrowableFormatter throwableFormatter) { return new Logger.Builder().throwableFormatter(throwableFormatter); } /** * Start to customize a {@link Logger} and set the {@link ThreadFormatter}. * * @param threadFormatter the {@link ThreadFormatter} to customize * @return the {@link Logger.Builder} to build the {@link Logger} */ public static Logger.Builder threadFormatter(ThreadFormatter threadFormatter) { return new Logger.Builder().threadFormatter(threadFormatter); } /** * Start to customize a {@link Logger} and set the {@link StackTraceFormatter}. * * @param stackTraceFormatter the {@link StackTraceFormatter} to customize * @return the {@link Logger.Builder} to build the {@link Logger} */ public static Logger.Builder stackTraceFormatter(StackTraceFormatter stackTraceFormatter) { return new Logger.Builder().stackTraceFormatter(stackTraceFormatter); } /** * Start to customize a {@link Logger} and set the {@link BorderFormatter}. * * @param borderFormatter the {@link BorderFormatter} to customize * @return the {@link Logger.Builder} to build the {@link Logger} */ public static Logger.Builder borderFormatter(BorderFormatter borderFormatter) { return new Logger.Builder().borderFormatter(borderFormatter); } /** * Start to customize a {@link Logger} and add an object formatter for specific class of object. * * @param objectClass the class of object * @param objectFormatter the object formatter to add * @param <T> the type of object * @return the {@link Logger.Builder} to build the {@link Logger} * @since 1.1.0 */ public static <T> Logger.Builder addObjectFormatter(Class<T> objectClass, ObjectFormatter<? super T> objectFormatter) { return new Logger.Builder().addObjectFormatter(objectClass, objectFormatter); } /** * Start to customize a {@link Logger} and add an interceptor. * * @param interceptor the interceptor to add * @return the {@link Logger.Builder} to build the {@link Logger} * @since 1.3.0 */ public static Logger.Builder addInterceptor(Interceptor interceptor) { return new Logger.Builder().addInterceptor(interceptor); } /** * Start to customize a {@link Logger} and set the {@link Printer} array. * * @param printers the {@link Printer} array to customize * @return the {@link Logger.Builder} to build the {@link Logger} */ public static Logger.Builder printers(Printer... printers) { return new Logger.Builder().printers(printers); } /** * Log an object with level {@link LogLevel#VERBOSE}. * * @param object the object to log * @see LogConfiguration.Builder#addObjectFormatter(Class, ObjectFormatter) * @since 1.1.0 */ public static void v(Object object) { assertInitialization(); sLogger.v(object); } /** * Log an array with level {@link LogLevel#VERBOSE}. * * @param array the array to log */ public static void v(Object[] array) { assertInitialization(); sLogger.v(array); } /** * Log a message with level {@link LogLevel#VERBOSE}. * * @param format the format of the message to log * @param args the arguments of the message to log */ public static void v(String format, Object... args) { assertInitialization(); sLogger.v(format, args); } /** * Log a message with level {@link LogLevel#VERBOSE}. * * @param msg the message to log */ public static void v(String msg) { assertInitialization(); sLogger.v(msg); } /** * Log a message and a throwable with level {@link LogLevel#VERBOSE}. * * @param msg the message to log * @param tr the throwable to be log */ public static void v(String msg, Throwable tr) { assertInitialization(); sLogger.v(msg, tr); } /** * Log an object with level {@link LogLevel#DEBUG}. * * @param object the object to log * @see LogConfiguration.Builder#addObjectFormatter(Class, ObjectFormatter) * @since 1.1.0 */ public static void d(Object object) { assertInitialization(); sLogger.d(object); } /** * Log an array with level {@link LogLevel#DEBUG}. * * @param array the array to log */ public static void d(Object[] array) { assertInitialization(); sLogger.d(array); } /** * Log a message with level {@link LogLevel#DEBUG}. * * @param format the format of the message to log * @param args the arguments of the message to log */ public static void d(String format, Object... args) { assertInitialization(); sLogger.d(format, args); } /** * Log a message with level {@link LogLevel#DEBUG}. * * @param msg the message to log */ public static void d(String msg) { assertInitialization(); sLogger.d(msg); } /** * Log a message and a throwable with level {@link LogLevel#DEBUG}. * * @param msg the message to log * @param tr the throwable to be log */ public static void d(String msg, Throwable tr) { assertInitialization(); sLogger.d(msg, tr); } /** * Log an object with level {@link LogLevel#INFO}. * * @param object the object to log * @see LogConfiguration.Builder#addObjectFormatter(Class, ObjectFormatter) * @since 1.1.0 */ public static void i(Object object) { assertInitialization(); sLogger.i(object); } /** * Log an array with level {@link LogLevel#INFO}. * * @param array the array to log */ public static void i(Object[] array) { assertInitialization(); sLogger.i(array); } /** * Log a message with level {@link LogLevel#INFO}. * * @param format the format of the message to log * @param args the arguments of the message to log */ public static void i(String format, Object... args) { assertInitialization(); sLogger.i(format, args); } /** * Log a message with level {@link LogLevel#INFO}. * * @param msg the message to log */ public static void i(String msg) { assertInitialization(); sLogger.i(msg); } /** * Log a message and a throwable with level {@link LogLevel#INFO}. * * @param msg the message to log * @param tr the throwable to be log */ public static void i(String msg, Throwable tr) { assertInitialization(); sLogger.i(msg, tr); } /** * Log an object with level {@link LogLevel#WARN}. * * @param object the object to log * @see LogConfiguration.Builder#addObjectFormatter(Class, ObjectFormatter) * @since 1.1.0 */ public static void w(Object object) { assertInitialization(); sLogger.w(object); } /** * Log an array with level {@link LogLevel#WARN}. * * @param array the array to log */ public static void w(Object[] array) { assertInitialization(); sLogger.w(array); } /** * Log a message with level {@link LogLevel#WARN}. * * @param format the format of the message to log * @param args the arguments of the message to log */ public static void w(String format, Object... args) { assertInitialization(); sLogger.w(format, args); } /** * Log a message with level {@link LogLevel#WARN}. * * @param msg the message to log */ public static void w(String msg) { assertInitialization(); sLogger.w(msg); } /** * Log a message and a throwable with level {@link LogLevel#WARN}. * * @param msg the message to log * @param tr the throwable to be log */ public static void w(String msg, Throwable tr) { assertInitialization(); sLogger.w(msg, tr); } /** * Log an object with level {@link LogLevel#ERROR}. * * @param object the object to log * @see LogConfiguration.Builder#addObjectFormatter(Class, ObjectFormatter) * @since 1.1.0 */ public static void e(Object object) { assertInitialization(); sLogger.e(object); } /** * Log an array with level {@link LogLevel#ERROR}. * * @param array the array to log */ public static void e(Object[] array) { assertInitialization(); sLogger.e(array); } /** * Log a message with level {@link LogLevel#ERROR}. * * @param format the format of the message to log * @param args the arguments of the message to log */ public static void e(String format, Object... args) { assertInitialization(); sLogger.e(format, args); } /** * Log a message with level {@link LogLevel#ERROR}. * * @param msg the message to log */ public static void e(String msg) { assertInitialization(); sLogger.e(msg); } /** * Log a message and a throwable with level {@link LogLevel#ERROR}. * * @param msg the message to log * @param tr the throwable to be log */ public static void e(String msg, Throwable tr) { assertInitialization(); sLogger.e(msg, tr); } /** * Log an object with specific log level. * * @param logLevel the specific log level * @param object the object to log * @see LogConfiguration.Builder#addObjectFormatter(Class, ObjectFormatter) * @since 1.4.0 */ public static void log(int logLevel, Object object) { assertInitialization(); sLogger.log(logLevel, object); } /** * Log an array with specific log level. * * @param logLevel the specific log level * @param array the array to log * @since 1.4.0 */ public static void log(int logLevel, Object[] array) { assertInitialization(); sLogger.log(logLevel, array); } /** * Log a message with specific log level. * * @param logLevel the specific log level * @param format the format of the message to log * @param args the arguments of the message to log * @since 1.4.0 */ public static void log(int logLevel, String format, Object... args) { assertInitialization(); sLogger.log(logLevel, format, args); } /** * Log a message with specific log level. * * @param logLevel the specific log level * @param msg the message to log * @since 1.4.0 */ public static void log(int logLevel, String msg) { assertInitialization(); sLogger.log(logLevel, msg); } /** * Log a message and a throwable with specific log level. * * @param logLevel the specific log level * @param msg the message to log * @param tr the throwable to be log * @since 1.4.0 */ public static void log(int logLevel, String msg, Throwable tr) { assertInitialization(); sLogger.log(logLevel, msg, tr); } /** * Log a JSON string, with level {@link LogLevel#DEBUG} by default. * * @param json the JSON string to log */ public static void json(String json) { assertInitialization(); sLogger.json(json); } /** * Log a XML string, with level {@link LogLevel#DEBUG} by default. * * @param xml the XML string to log */ public static void xml(String xml) { assertInitialization(); sLogger.xml(xml); } /** * Compatible class with {@link android.util.Log}. * * @deprecated please use {@link XLog} instead */ public static class Log { /** * @deprecated compatible with {@link android.util.Log#v(String, String)} */ public static void v(String tag, String msg) { tag(tag).build().v(msg); } /** * @deprecated compatible with {@link android.util.Log#v(String, String, Throwable)} */ public static void v(String tag, String msg, Throwable tr) { tag(tag).build().v(msg, tr); } /** * @deprecated compatible with {@link android.util.Log#d(String, String)} */ public static void d(String tag, String msg) { tag(tag).build().d(msg); } /** * @deprecated compatible with {@link android.util.Log#d(String, String, Throwable)} */ public static void d(String tag, String msg, Throwable tr) { tag(tag).build().d(msg, tr); } /** * @deprecated compatible with {@link android.util.Log#i(String, String)} */ public static void i(String tag, String msg) { tag(tag).build().i(msg); } /** * @deprecated compatible with {@link android.util.Log#i(String, String, Throwable)} */ public static void i(String tag, String msg, Throwable tr) { tag(tag).build().i(msg, tr); } /** * @deprecated compatible with {@link android.util.Log#w(String, String)} */ public static void w(String tag, String msg) { tag(tag).build().w(msg); } /** * @deprecated compatible with {@link android.util.Log#w(String, String, Throwable)} */ public static void w(String tag, String msg, Throwable tr) { tag(tag).build().w(msg, tr); } /** * @deprecated compatible with {@link android.util.Log#w(String, Throwable)} */ public static void w(String tag, Throwable tr) { tag(tag).build().w("", tr); } /** * @deprecated compatible with {@link android.util.Log#e(String, String)} */ public static void e(String tag, String msg) { tag(tag).build().e(msg); } /** * @deprecated compatible with {@link android.util.Log#e(String, String, Throwable)} */ public static void e(String tag, String msg, Throwable tr) { tag(tag).build().e(msg, tr); } /** * @deprecated compatible with {@link android.util.Log#wtf(String, String)} */ public static void wtf(String tag, String msg) { e(tag, msg); } /** * @deprecated compatible with {@link android.util.Log#wtf(String, Throwable)} */ public static void wtf(String tag, Throwable tr) { wtf(tag, "", tr); } /** * @deprecated compatible with {@link android.util.Log#wtf(String, String, Throwable)} */ public static void wtf(String tag, String msg, Throwable tr) { e(tag, msg, tr); } /** * @deprecated compatible with {@link android.util.Log#println(int, String, String)} */ public static void println(int logLevel, String tag, String msg) { tag(tag).build().println(logLevel, msg); } /** * @deprecated compatible with {@link android.util.Log#isLoggable(String, int)} */ public static boolean isLoggable(String tag, int level) { return sLogConfiguration.isLoggable(level); } /** * @deprecated compatible with {@link android.util.Log#getStackTraceString(Throwable)} */ public static String getStackTraceString(Throwable tr) { return StackTraceUtil.getStackTraceString(tr); } } }