com.mobicage.rogerthat.util.logging.L.java Source code

Java tutorial

Introduction

Here is the source code for com.mobicage.rogerthat.util.logging.L.java

Source

/*
 * Copyright 2016 Mobicage NV
 *
 * 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.
 *
 * @@license_version:1.1@@
 */

package com.mobicage.rogerthat.util.logging;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.json.simple.JSONObject;

import android.os.AsyncTask;
import android.os.Build;
import android.util.Log;

import com.mobicage.api.system.Rpc;
import com.mobicage.rogerthat.MainService;
import com.mobicage.rogerthat.registration.RegistrationWizard2;
import com.mobicage.rogerthat.util.http.HTTPUtil;
import com.mobicage.rogerthat.util.system.SafeRunnable;
import com.mobicage.rogerthat.util.system.SystemUtils;
import com.mobicage.rogerthat.util.system.T;
import com.mobicage.rpc.ResponseHandler;
import com.mobicage.rpc.config.CloudConstants;
import com.mobicage.to.system.LogErrorRequestTO;
import com.mobicage.to.system.LogErrorResponseTO;

/**
 * Logging class to android.util.Log all messages with logtag "MC"
 * 
 */
public class L {

    public final static String SEPARATOR = "------------------------------------------------------";
    public final static String TAG = "MC";
    private final static String BUG = "Bug!";
    private final static int BLOB_PIECE_SIZE = 120;
    private final static String BLOB_LINE_PREFIX = "   ";

    private final static long MAX_SEND_RATE = 1000 * 60 * 60; // 1 hour

    private static volatile long sLastErrorLogTimestamp = 0;
    private static volatile MainService sMainService;

    public static void dBlob(String blob) {
        String[] logLines = blob.split("\\r?\\n");
        L.d(L.SEPARATOR);
        for (String logLine : logLines) {
            int numPieces = 1 + (logLine.length() / BLOB_PIECE_SIZE);
            for (int i = 0; i < numPieces; i++) {
                if (i < numPieces - 1) {
                    L.d(BLOB_LINE_PREFIX + logLine.substring(i * BLOB_PIECE_SIZE, (i + 1) * BLOB_PIECE_SIZE));
                } else {
                    L.d(BLOB_LINE_PREFIX + logLine.substring(i * BLOB_PIECE_SIZE));
                }
            }
        }
        L.d(L.SEPARATOR);
    }

    // Android-only log, not to SD
    public static void dd(String s) {
        Log.d(TAG, s);
    }

    // Android-only log, not to SD
    public static void dd(Throwable t) {
        Log.d(TAG, "", t);
    }

    // Android-only log, not to SD
    public static void dd(String s, Throwable t) {
        Log.d(TAG, s, t);
    }

    public static void highlight(String s) {
        d(SEPARATOR);
        d(s);
        d(SEPARATOR);
    }

    public static void bug(String s) {
        s = BUG + '\n' + s;
        Log.d(TAG, s);
        logToServer(s, null);
        logToXmpp("BUG", s, null);
    }

    public static void bug(Throwable t) {
        Log.d(TAG, BUG, t);
        logToServer(null, t);
        logToXmpp("BUG", "", t);
    }

    private static void setErrorMessageOnLogErrorRequest(Throwable t, LogErrorRequestTO request) {
        request.errorMessage = getStackTraceString(t);
    }

    public static String getStackTraceString(Throwable t) {
        final Writer w = new StringWriter();
        final PrintWriter pw = new PrintWriter(w);
        t.printStackTrace(pw);
        return w.toString();
    }

    public static void bug(String s, Throwable t) {
        s = BUG + '\n' + s;
        Log.d(TAG, s, t);
        logToServer(s, t);
        logToXmpp("BUG", s, t);
    }

    private static void logToServer(final String s, final Throwable t) {
        try {
            if (sMainService == null)
                return;
            final long currentTimeMillis = sMainService.currentTimeMillis();
            if (currentTimeMillis - sLastErrorLogTimestamp < MAX_SEND_RATE)
                return;
            sLastErrorLogTimestamp = currentTimeMillis;
            try {
                throw new Exception();
            } catch (final Exception e) {
                if (sMainService.getRegisteredFromConfig()) {
                    sMainService.postOnUIHandler(new SafeRunnable() {
                        @Override
                        protected void safeRun() throws Exception {
                            if (sMainService == null)
                                return;
                            LogErrorRequestTO request = new LogErrorRequestTO();
                            request.description = s;
                            request.platform = 1;
                            request.timestamp = currentTimeMillis / 1000;
                            request.mobicageVersion = (sMainService.isDebug() ? "-" : "")
                                    + sMainService.getMajorVersion() + "." + sMainService.getMinorVersion();
                            request.platformVersion = Build.FINGERPRINT + " (-) " + SystemUtils.getAndroidVersion()
                                    + " (-) " + Build.MODEL;
                            setErrorMessageOnLogErrorRequest(t == null ? e : t, request);
                            Rpc.logError(new ResponseHandler<LogErrorResponseTO>(), request);
                        }
                    });
                } else {
                    new AsyncTask<Object, Object, Object>() {
                        @Override
                        protected Object doInBackground(Object... params) {
                            if (sMainService == null)
                                return null;
                            try {
                                HttpPost httpPostRequest = new HttpPost(CloudConstants.LOG_ERROR_URL);
                                httpPostRequest.setHeader("Content-Type", "application/x-www-form-urlencoded");

                                RegistrationWizard2 wiz = RegistrationWizard2.getWizard(sMainService);

                                List<NameValuePair> formParams = new ArrayList<NameValuePair>();
                                formParams.add(new BasicNameValuePair("install_id", wiz.getInstallationId()));
                                formParams.add(new BasicNameValuePair("device_id", wiz.getDeviceId()));
                                formParams
                                        .add(new BasicNameValuePair("language", Locale.getDefault().getLanguage()));
                                formParams.add(new BasicNameValuePair("country", Locale.getDefault().getCountry()));
                                formParams.add(new BasicNameValuePair("description", s));
                                formParams.add(new BasicNameValuePair("platform", "1"));
                                formParams.add(new BasicNameValuePair("platform_version",
                                        "" + SystemUtils.getAndroidVersion()));
                                formParams.add(new BasicNameValuePair("timestamp",
                                        "" + System.currentTimeMillis() / 1000));
                                formParams.add(new BasicNameValuePair("mobicage_version",
                                        MainService.getVersion(sMainService)));
                                formParams.add(new BasicNameValuePair("error_message",
                                        getStackTraceString(t == null ? e : t)));

                                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, HTTP.UTF_8);
                                httpPostRequest.setEntity(entity);
                                HTTPUtil.getHttpClient().execute(httpPostRequest);
                            } catch (Exception e1) {
                                L.d("Error while posting error to server", e1);
                            }
                            return null;
                        }
                    }.execute();
                }
            }
        } catch (Exception e) {
            L.d("Error while posting error to server", e);
        }
    }

    public static void d(String s) {
        if (CloudConstants.DEBUG_LOGGING)
            Log.d(TAG, s);

        logToXmpp("D", s, null);
    }

    public static void d(Throwable t) {
        if (CloudConstants.DEBUG_LOGGING)
            Log.d(TAG, "", t);

        logToXmpp("D", "", t);
    }

    public static void d(String s, Throwable t) {
        if (CloudConstants.DEBUG_LOGGING)
            Log.d(TAG, s, t);

        logToXmpp("D", s, t);
    }

    public static void e(String s) {
        Log.e(TAG, s);
        logToXmpp("E", s, null);
    }

    public static void e(Throwable t) {
        Log.e(TAG, "", t);
        logToXmpp("E", "", t);
    }

    public static void e(String s, Throwable t) {
        Log.e(TAG, s, t);
        logToXmpp("E", s, t);
    }

    public static void i(String s) {
        Log.i(TAG, s);
        logToXmpp("I", s, null);
    }

    public static void i(Throwable t) {
        Log.i(TAG, "", t);
        logToXmpp("I", "", t);
    }

    public static void i(String s, Throwable t) {
        Log.i(TAG, s, t);
        logToXmpp("I", s, t);
    }

    public static void v(String s) {
        Log.v(TAG, s);
    }

    public static void v(Throwable t) {
        Log.v(TAG, "", t);
    }

    public static void v(String s, Throwable t) {
        if (CloudConstants.DEBUG_LOGGING)
            Log.v(TAG, s, t);
    }

    public static void w(String s) {
        Log.w(TAG, s);
        logToXmpp("W", s, null);
    }

    public static void w(Throwable t) {
        Log.w(TAG, "", t);
        logToXmpp("W", "", t);
    }

    public static void w(String s, Throwable t) {
        Log.w(TAG, s, t);
        logToXmpp("W", s, t);
    }

    public static void setContext(MainService mainService) {
        sMainService = mainService;
    }

    public static void logStackTrace() {
        try {
            throw new Exception("Debug Exception");
        } catch (Exception e) {
            L.d(e);
        }
    }

    public static class LogForwarder implements Runnable {

        private class LogItem {

            private final long timestamp;
            private final String threadName;
            private final String logLevel;
            private final String logLine;
            private final Throwable throwable;

            LogItem(final String logLevel, final String logLine, final Throwable throwable) {
                this.timestamp = sMainService == null ? System.currentTimeMillis()
                        : sMainService.currentTimeMillis();
                this.threadName = T.getThreadName();
                this.logLevel = logLevel;
                this.logLine = logLine;
                this.throwable = throwable;
            }
        }

        private boolean forwarding;
        private String jid;
        private Thread forwardingThread;
        private final BlockingDeque<LogItem> queue;
        private final LogItem stopper = new LogItem(null, null, null);

        LogForwarder() {
            this.forwarding = false;
            this.queue = new LinkedBlockingDeque<LogItem>();
        }

        public void start(final String jid) {
            synchronized (this) {
                if (this.forwarding)
                    return;
                this.jid = jid;
                this.forwarding = true;
                this.queue.clear();
                this.forwardingThread = new Thread(this);
                this.forwardingThread.setDaemon(true);
                this.forwardingThread.start();
            }
        }

        public void stop() {
            synchronized (this) {
                if (!this.forwarding)
                    return;
                this.forwarding = false;
                this.queue.add(this.stopper);
                this.forwardingThread = null;
            }
        }

        public void queue(final String logLevel, final String logLine, final Throwable throwable) {
            if (!this.forwarding)
                return;
            this.queue.add(new LogItem(logLevel, logLine, throwable));
        }

        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            thread_loop: while (true) {
                LogItem li;
                // Wait and take 1 item from the queue
                try {
                    li = queue.take();
                } catch (InterruptedException e) {
                    break thread_loop;
                }
                if (li == this.stopper)
                    break thread_loop;

                final StringBuilder sb = new StringBuilder();
                formatLogLine(li, sb);

                empty_queue_loop: while (true) { // Loop until all items are taken from the queue
                    li = queue.poll();
                    if (li != null) {
                        if (li == this.stopper)
                            break thread_loop;
                        sb.append('\n');
                        formatLogLine(li, sb);
                    } else
                        break empty_queue_loop;
                }

                JSONObject result = new JSONObject();
                result.put("jid", this.jid);
                result.put("message", sb.toString());

                ByteArrayEntity bae = new ByteArrayEntity(result.toJSONString().getBytes(Charset.forName("UTF-8")));
                HttpPost post = new HttpPost(CloudConstants.DEBUG_LOG_URL);
                post.setEntity(bae);
                try {
                    HTTPUtil.getHttpClient().execute(post);
                } catch (ClientProtocolException e) {
                    // Cannot log due to prevent log loops
                } catch (IOException e) {
                    // Cannot log due to prevent log loops
                }
            }
        }

        private void formatLogLine(LogItem li, StringBuilder sb) {
            sb.append(li.timestamp).append(' ').append(li.threadName).append(' ').append(li.logLevel).append(" - ")
                    .append(li.logLine);
            if (li.throwable != null) {
                sb.append('\n').append(getStackTraceString(li.throwable));
            }
        }
    }

    private final static LogForwarder logForwarder = new LogForwarder();

    public static LogForwarder getLogForwarder() {
        return logForwarder;
    }

    private static void logToXmpp(final String logLevel, final String logLine, final Throwable throwable) {
        logForwarder.queue(logLevel, logLine, throwable);
    }
}