<commit_before>package org.mym.plog;

import android.text.TextUtils;
import android.util.Log;

import org.mym.plog.config.Logger;
import org.mym.plog.config.PLogConfig;
import org.mym.plog.util.ObjectUtil;
import org.mym.plog.util.TimingLogger;

/**
 * Entry class of log module, settings, and init configs are all here.
 *
 * <p>You don't need to create this class since it is only an utility class, for configs,
 * please use {@link #init(PLogConfig)}. <br>
 * Also, it is strongly recommended to create config instance using
 * {@link org.mym.plog.config.PLogConfig.Builder}, instead of directly call constructor.
 * </p>
 * @author Muyangmin
 * @since 1.0.0
 */
@SuppressWarnings("unused")
public final class PLog {

    /**
     * 0 dalvik.system.VMStack.getThreadStackTrace(Native Method)       <br/>
     * 1 java.lang.Thread.getStackTrace(Thread.java:579)                <br/>
     * 2 {@link #getLineNumAndMethodName(int)}                             <br/>
     * 3 {@link #wrapLogStr(int, String, Object...)}                         <br/>
     * 4 {@link #log(int, int, String, String, Object...)}                   <br/>
     * 5 v, d, i, w, e                                                  <br/>
     * 6 invoker
     */
    private static final int STACK_TRACE_INDEX = 6;

    private static PLogConfig mConfig;
    private static TimingLogger mTimingLogger;

    //The constructor of this class is meaningless, so make it private
    private PLog(){
        //Empty
    }

    /**
     * Check and set {@link #mConfig} field. this operation guarantee the reading of config for
     * later operation is safe.
     */
    private static synchronized void safelySetConfig(PLogConfig config) throws RuntimeException {
        PLogConfig.checkConfigSafe(config);
        mConfig = config;
    }

    /**
     * Init PLog using customized config.
     */
    public static void init(PLogConfig config) {
        safelySetConfig(config);
    }

    /**
     * Get current config; maybe this is useful for temporarily change config and backup then.
     * Another scenario is to debug this library.
     * @return Current config; or default config if {@link #init(PLogConfig)} is not called yet.
     * @see #init(PLogConfig)
     * @since 1.3.0
     */
    public static PLogConfig getCurrentConfig(){
        checkInitOrUseDefaultConfig();
        return mConfig;
    }

    /**
     * Add timing split, the meaning of this operation is same as standard TimingLogger.
     */
    public static void addTimingSplit(String splitLabel) {
        mTimingLogger.addSplit(splitLabel);
    }

    /**
     * Dump timing log using current logger.
     */
    public static void dumpTimingToLog() {
        mTimingLogger.dumpToLog();
    }

    /**
     * Reset timing logger. A creation maybe needed if never called timing fucntion.
     *
     * @see android.util.TimingLogger
     */
    public static void resetTimingLogger(String tag, String label) {
        if (mTimingLogger == null) {
            mTimingLogger = createDefaultTimingLogger();
        }
        mTimingLogger.reset(tag, label);
    }

    /**
     * Reset timing logger.
     */
    public static void resetTimingLogger() {
        if (mTimingLogger == null) {
            mTimingLogger = createDefaultTimingLogger();
        }
        mTimingLogger.reset();
    }

    private static TimingLogger createDefaultTimingLogger() {
        return new TimingLogger("PLogTiming", "TimingLabel");
    }

    public static void v(String msg, Object... params) {
        log(Log.VERBOSE, 0, null, msg, params);
    }

    public static void v(String tag, String msg, Object... params) {
        log(Log.VERBOSE, 0, tag, msg, params);
    }

    public static void d(String msg, Object... params) {
        log(Log.DEBUG, 0, null, msg, params);
    }

    public static void d(String tag, String msg, Object... params) {
        log(Log.DEBUG, 0, tag, msg, params);
    }

    public static void i(String msg, Object... params) {
        log(Log.INFO, 0, null, msg, params);
    }

    public static void i(String tag, String msg, Object... params) {
        log(Log.INFO, 0, tag, msg, params);
    }

    public static void w(String msg, Object... params) {
        log(Log.WARN, 0, null, msg, params);
    }

    public static void w(String tag, String msg, Object... params) {
        log(Log.WARN, 0, tag, msg, params);
    }

    public static void e(String msg, Object... params) {
        log(Log.ERROR, 0, null, msg, params);
    }

    public static void e(String tag, String msg, Object... params) {
        log(Log.ERROR, 0, tag, msg, params);
    }

    /**
     * Print {@link PLogConfig#getEmptyMsg()}, using DEBUG Level,
     * or {@link PLogConfig#getEmptyMsgLevel()} if specified.
     */
    public static void empty() {
        int level = mConfig == null ? Log.DEBUG : mConfig.getEmptyMsgLevel();
        log(level, 0, null, null);
    }

    /**
     * Use this method for skipping some middle methods, if necessary.
     * <p><strong>Note: This method is often not recommend; v,d,i,w,e methods is enough for common
     * use.</strong></p>
     * @param level log level, MUST be one of
     *              {@link Log#VERBOSE}, {@link Log#DEBUG}, {@link Log#INFO},
     *              {@link Log#WARN}, {@link Log#ERROR}.
     * @param stackOffset stack offset, often pass an non-negative integer, the default log is 0.
     * @param tag log tag.
     * @param msg log message.
     * @param params log params, optional.
     */
    public static void logWithStackOffset(int level, int stackOffset, String tag, String msg,
                                          Object... params){
        //Just transfer to log() method, for keep same layer level with v,d,i,w,e methods.
        log(level, stackOffset, tag, msg, params);
    }

    /**
     * A helper method useful when you just want to print objects using default format.
     * The log level for this method is defined as {@link Log#INFO}.
     * @param params objects to print.
     */
    public static void objects(Object... params){
        log(Log.INFO, 0, null, null, params);
    }

    /**
     * A helper method useful when you just want to print objects using default format.
     * @param level log level.
     * @param params objects to print.
     */
    public static void objects(int level, Object... params){
        log(level, 0, null, null, params);
    }

    /**
     * Core method : internal implementation.
     */
    private static void log(int level, int stackOffset, String tag, String msg, Object... params) {
        checkInitOrUseDefaultConfig();

        //Checking for auto tag
        if (TextUtils.isEmpty(tag) && mConfig.isUseAutoTag()) {
            tag = getAutoTag(stackOffset);
        }
        //Only concat when tag is not empty and config is specified to true
        if ((!TextUtils.isEmpty(tag)) && mConfig.isForceConcatGlobalTag()) {
            tag = mConfig.getGlobalTag() + "-" + tag;
        }
        //If still empty, using global
        else if (TextUtils.isEmpty(tag)) {
            tag = mConfig.getGlobalTag();
        }

        //If loggable, print it
        if (mConfig.getController().isLogEnabled(level, tag, msg)) {
            String logContent = wrapLogStr(stackOffset, msg, params);
            Logger logger = mConfig.getLogger();

            int maxLengthPerLine = mConfig.getMaxLengthPerLine();
            int currentIndex = 0;

            //Use a StringBuilder to build multi line text but print only once, solve #6
            StringBuilder sb = new StringBuilder(logContent.length()<commit_msg>Add exceptions and wtf bonus methods. : )<commit_after>package org.mym.plog;

import android.text.TextUtils;
import android.util.Log;

import org.mym.plog.config.Logger;
import org.mym.plog.config.PLogConfig;
import org.mym.plog.util.ObjectUtil;
import org.mym.plog.util.TimingLogger;

/**
 * Entry class of log module, settings, and init configs are all here.
 *
 * <p>You don't need to create this class since it is only an utility class, for configs,
 * please use {@link #init(PLogConfig)}. <br>
 * Also, it is strongly recommended to create config instance using
 * {@link org.mym.plog.config.PLogConfig.Builder}, instead of directly call constructor.
 * </p>
 * @author Muyangmin
 * @since 1.0.0
 */
@SuppressWarnings("unused")
public final class PLog {

    /**
     * 0 dalvik.system.VMStack.getThreadStackTrace(Native Method)       <br/>
     * 1 java.lang.Thread.getStackTrace(Thread.java:579)                <br/>
     * 2 {@link #getLineNumAndMethodName(int)}                             <br/>
     * 3 {@link #wrapLogStr(int, String, Object...)}                         <br/>
     * 4 {@link #log(int, int, String, String, Object...)}                   <br/>
     * 5 v, d, i, w, e                                                  <br/>
     * 6 invoker
     */
    private static final int STACK_TRACE_INDEX = 6;

    private static PLogConfig mConfig;
    private static TimingLogger mTimingLogger;

    //The constructor of this class is meaningless, so make it private
    private PLog(){
        //Empty
    }

    /**
     * Check and set {@link #mConfig} field. this operation guarantee the reading of config for
     * later operation is safe.
     */
    private static synchronized void safelySetConfig(PLogConfig config) throws RuntimeException {
        PLogConfig.checkConfigSafe(config);
        mConfig = config;
    }

    /**
     * Init PLog using customized config.
     */
    public static void init(PLogConfig config) {
        safelySetConfig(config);
    }

    /**
     * Get current config; maybe this is useful for temporarily change config and backup then.
     * Another scenario is to debug this library.
     * @return Current config; or default config if {@link #init(PLogConfig)} is not called yet.
     * @see #init(PLogConfig)
     * @since 1.3.0
     */
    public static PLogConfig getCurrentConfig(){
        checkInitOrUseDefaultConfig();
        return mConfig;
    }

    /**
     * Add timing split, the meaning of this operation is same as standard TimingLogger.
     */
    public static void addTimingSplit(String splitLabel) {
        mTimingLogger.addSplit(splitLabel);
    }

    /**
     * Dump timing log using current logger.
     */
    public static void dumpTimingToLog() {
        mTimingLogger.dumpToLog();
    }

    /**
     * Reset timing logger. A creation maybe needed if never called timing fucntion.
     *
     * @see android.util.TimingLogger
     */
    public static void resetTimingLogger(String tag, String label) {
        if (mTimingLogger == null) {
            mTimingLogger = createDefaultTimingLogger();
        }
        mTimingLogger.reset(tag, label);
    }

    /**
     * Reset timing logger.
     */
    public static void resetTimingLogger() {
        if (mTimingLogger == null) {
            mTimingLogger = createDefaultTimingLogger();
        }
        mTimingLogger.reset();
    }

    private static TimingLogger createDefaultTimingLogger() {
        return new TimingLogger("PLogTiming", "TimingLabel");
    }

    public static void v(String msg, Object... params) {
        log(Log.VERBOSE, 0, null, msg, params);
    }

    public static void v(String tag, String msg, Object... params) {
        log(Log.VERBOSE, 0, tag, msg, params);
    }

    public static void d(String msg, Object... params) {
        log(Log.DEBUG, 0, null, msg, params);
    }

    public static void d(String tag, String msg, Object... params) {
        log(Log.DEBUG, 0, tag, msg, params);
    }

    public static void i(String msg, Object... params) {
        log(Log.INFO, 0, null, msg, params);
    }

    public static void i(String tag, String msg, Object... params) {
        log(Log.INFO, 0, tag, msg, params);
    }

    public static void w(String msg, Object... params) {
        log(Log.WARN, 0, null, msg, params);
    }

    public static void w(String tag, String msg, Object... params) {
        log(Log.WARN, 0, tag, msg, params);
    }

    public static void e(String msg, Object... params) {
        log(Log.ERROR, 0, null, msg, params);
    }

    public static void e(String tag, String msg, Object... params) {
        log(Log.ERROR, 0, tag, msg, params);
    }

    /**
     * Print {@link PLogConfig#getEmptyMsg()}, using DEBUG Level,
     * or {@link PLogConfig#getEmptyMsgLevel()} if specified.
     */
    public static void empty() {
        int level = mConfig == null ? Log.DEBUG : mConfig.getEmptyMsgLevel();
        log(level, 0, null, null);
    }

    /**
     * Use this method for skipping some middle methods, if necessary.
     * <p><strong>Note: This method is often not recommend; v,d,i,w,e methods is enough for common
     * use.</strong></p>
     * @param level log level, MUST be one of
     *              {@link Log#VERBOSE}, {@link Log#DEBUG}, {@link Log#INFO},
     *              {@link Log#WARN}, {@link Log#ERROR}.
     * @param stackOffset stack offset, often pass an non-negative integer, the default log is 0.
     * @param tag log tag.
     * @param msg log message.
     * @param params log params, optional.
     */
    public static void logWithStackOffset(int level, int stackOffset, String tag, String msg,
                                          Object... params){
        //Just transfer to log() method, for keep same layer level with v,d,i,w,e methods.
        log(level, stackOffset, tag, msg, params);
    }

    /**
     * A helper method useful when you just want to print objects using default format.
     * The log level for this method is defined as {@link Log#INFO}.
     * @param params objects to print.
     */
    public static void objects(Object... params){
        log(Log.INFO, 0, null, null, params);
    }

    /**
     * A helper method useful when you just want to print objects using default format.
     * @param level log level.
     * @param params objects to print.
     */
    public static void objects(int level, Object... params){
        log(level, 0, null, null, params);
    }

    /**
     * Print exceptions in WARN level.
     */
    public static void exceptions(Throwable... params){
        log(Log.WARN, 0, null, null, params);
    }

    /**
     * Print exceptions in specified level.
     */
    public static void exceptions(int level, Throwable... params){
        log(level, 0, null, null, params);
    }

    /**
     * Print exceptions in ERROR level.
     */
    public static void wtf(Throwable params){
        log(Log.ERROR, 0, null, null, params);
    }

    /**
     * Core method : internal implementation.
     */
    private static void log(int level, int stackOffset, String tag, String msg, Object... params) {
        checkInitOrUseDefaultConfig();

        //Checking for auto tag
        if (TextUtils.isEmpty(tag) && mConfig.isUseAutoTag()) {
            tag = getAutoTag(stackOffset);
        }
        //Only concat when tag is not empty and config is specified to true
        if ((!TextUtils.isEmpty(tag)) && mConfig.isForceConcatGlobalTag()) {
            tag = mConfig.getGlobalTag() + "-" + tag;
        }
        //If still empty, using global
        else if (TextUtils.isEmpty(tag)) {
            tag = mConfig.getGlobalTag();
        }

        //If loggable, print it
        if (mConfig.getController().isLogEnabled(level, tag, msg)) {
            String logContent = wrapLogStr(stackOffset, msg, params);
            Logger logger = mConfig.getLogger();

            int maxLengthPerLine = mConfig.getMaxLengthPerLine();
            int currentIndex = 0;

            //Use a StringBuilder to build multi line text but print only once, solve #6
            StringBuilder sb = new StringBuilder(logContent.length()
{'fraction_non_alphanumeric': 0.11085010475525363, 'fraction_numerical': 0.004380674242905213, 'mean_word_length': 2.2545454545454544, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3300829', 'n_tokens_mistral': 4534, 'n_tokens_neox': 4416, 'n_words': 1504}