Android Tutorial - Core Class : Log
Use log
package app.test; import java.text.NumberFormat; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class Test extends Activity { @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); final EditText myEditField = (EditText) findViewById(R.id.mealprice); final TextView answerfield = (TextView) findViewById(R.id.answer); final Button button = (Button) findViewById(R.id.calculate); button.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { try { String mealprice = myEditField.getText().toString(); String answer = ""; if (mealprice.indexOf("$") == -1) { mealprice = "$" + mealprice; } NumberFormat nf = java.text.NumberFormat.getCurrencyInstance(); if (nf == null) { Log.i("", "NumberFormat is null"); } float fmp = nf.parse(mealprice).floatValue(); fmp *= 2; Log.i("", "Total:" + fmp); answer = "Full Price:" + nf.format(fmp); answerfield.setText(answer); } catch (java.text.ParseException pe) { Log.i("", "Parse exception caught"); answerfield.setText("Failed to parse amount?"); } catch (Exception e) { Log.e("", "Failed to Calculate Tip:" + e.getMessage()); e.printStackTrace(); answerfield.setText(e.getMessage()); } } }); } } // main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Calculator" /> <EditText android:id="@+id/mealprice" android:layout_width="fill_parent" android:layout_height="wrap_content" android:autoText="true" /> <Button android:id="@+id/calculate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Calculate Tip" /> <TextView android:id="@+id/answer" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="" /> </LinearLayout>
Log Utility
//package com.cloud.charts4a.util; import android.util.Log; class LogUtil { private LogUtil(){ } public static void debug(Class<?> clazz,String message){ Log.d(clazz.getName(), message); } public static void info(Class<?> clazz,String message){ Log.i(clazz.getName(), message); } public static void warn(Class<?> clazz,String message){ Log.w(clazz.getName(), message); } public static void warn(Class<?> clazz,String message,Throwable t){ Log.w(clazz.getName(), message,t); } public static void error(Class<?> clazz,String message){ Log.e(clazz.getName(), message); } public static void error(Class<?> clazz,String message,Throwable t){ Log.e(clazz.getName(), message,t); } }
Log events
package app.test; import android.app.Activity; import android.app.IntentService; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; public class Test extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); logEvent("CREATE"); } @Override public void onStart() { super.onStart(); logEvent("START"); } @Override public void onResume() { super.onResume(); logEvent("RESUME"); } @Override public void onPause() { super.onPause(); logWarning("PAUSE"); } @Override public void onStop() { super.onStop(); logWarning("STOP"); } @Override public void onDestroy() { super.onDestroy(); logWarning("DESTROY"); } private void logEvent(String event) { Intent intent = new Intent(this, OperationsManager.class); intent.setAction(OperationsManager.ACTION_EVENT); intent.putExtra(OperationsManager.EXTRA_NAME, event); startService(intent); } private void logWarning(String event) { Intent intent = new Intent(this, OperationsManager.class); intent.setAction(OperationsManager.ACTION_WARNING); intent.putExtra(OperationsManager.EXTRA_NAME, event); startService(intent); } } class OperationsManager extends IntentService { public static final String ACTION_EVENT = "ACTION_EVENT"; public static final String ACTION_WARNING = "ACTION_WARNING"; public static final String ACTION_ERROR = "ACTION_ERROR"; public static final String EXTRA_NAME = "eventName"; private static final String LOGTAG = "EventLogger"; private IntentFilter matcher; public OperationsManager() { super("OperationsManager"); matcher = new IntentFilter(); matcher.addAction(ACTION_EVENT); matcher.addAction(ACTION_WARNING); matcher.addAction(ACTION_ERROR); } @Override protected void onHandleIntent(Intent intent) { if (!matcher.matchAction(intent.getAction())) { Toast.makeText(this, "OperationsManager: Invalid Request", Toast.LENGTH_SHORT).show(); return; } if (TextUtils.equals(intent.getAction(), ACTION_EVENT)) { logEvent(intent.getStringExtra(EXTRA_NAME)); } } private void logEvent(String name) { try { Thread.sleep(5000); Log.i(LOGTAG, name); } catch (InterruptedException e) { e.printStackTrace(); } } }
Log your action
package app.test; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.RelativeLayout; public class Test extends Activity implements OnTouchListener { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); RelativeLayout layout1 = (RelativeLayout) findViewById(R.id.layout1); layout1.setOnTouchListener(this); } public boolean onTouch(View v, MotionEvent event) { String myTag = v.getTag().toString(); Log.v(myTag, describeEvent(event)); logAction(event); if( "true".equals(myTag.substring(0, 4))) { return true; } else { return false; } } protected static String describeEvent(MotionEvent event) { StringBuilder result = new StringBuilder(500); result.append("Action: ").append(event.getAction()).append("\n"); int numPointers = event.getPointerCount(); result.append("Number of pointers: ").append(numPointers).append("\n"); int ptrIdx = 0; while (ptrIdx < numPointers) { int ptrId = event.getPointerId(ptrIdx); result.append("Pointer Index: ").append(ptrIdx); result.append(", Pointer Id: ").append(ptrId).append("\n"); result.append(" Location: ").append(event.getX(ptrIdx)); result.append(" x ").append(event.getY(ptrIdx)).append("\n"); result.append(" Pressure: ").append(event.getPressure(ptrIdx)); result.append(" Size: ").append(event.getSize(ptrIdx)).append("\n"); ptrIdx++; } result.append("Downtime: ").append(event.getDownTime()).append("ms\n"); result.append("Event time: ").append(event.getEventTime()).append("ms"); result.append(" Elapsed: ").append(event.getEventTime()-event.getDownTime()); result.append(" ms\n"); return result.toString(); } private void logAction(MotionEvent event) { final String TAG = "Action"; int ptrIndex = event.getActionIndex(); int ptrId = event.getPointerId(ptrIndex); int action = event.getActionMasked(); Log.v(TAG, "Pointer index: " + ptrIndex); Log.v(TAG, "Pointer Id: " + ptrId); Log.v(TAG, "True action value: " + action); } } //main.xml <?xml version="1.0" encoding="utf-8"?> <!-- This file is /res/layout/main.xml --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout1" android:tag="trueLayout" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" > <TextView android:text="Touch fingers on the screen and look at LogCat" android:id="@+id/message" android:tag="trueText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" /> </RelativeLayout>
Write an activity that looks like a pop-up dialog with a custom theme using a different text color.
package com.example.android.apis.app; import com.example.android.apis.R; import android.app.Activity; import android.os.Bundle; public class CustomDialogActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.custom_dialog_activity); } } //layout/custom_dialog_activity.xml <?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical|center_horizontal" android:text="custom_dialog_activity_text"/>
Responsible for delegating calls to the Android logging system.
//package org.acra.log; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import android.util.Log; public final class NonAndroidLog { // Not that it really matters but these levels match those used in Android.util.Log public static final int VERBOSE = 2; public static final int DEBUG = 3; public static final int INFO = 4; public static final int WARN = 5; public static final int ERROR = 6; //public static final int ASSERT = 7; private int logLevel = VERBOSE; private final PrintStream out = System.out; public void setLogLevel(int logLevel) { this.logLevel = logLevel; } public int v(String tag, String msg) { if (logLevel <= VERBOSE) { out.println(tag + " : " + msg); } return 0; } public int v(String tag, String msg, Throwable tr) { if (logLevel <= VERBOSE) { out.println(tag + " : " + msg); tr.printStackTrace(out); } return 0; } public int d(String tag, String msg) { if (logLevel <= DEBUG) { out.println(tag + " : " + msg); } return 0; } public int d(String tag, String msg, Throwable tr) { if (logLevel <= DEBUG) { out.println(tag + " : " + msg); tr.printStackTrace(out); } return 0; } public int i(String tag, String msg) { if (logLevel <= INFO) { out.println(tag + " : " + msg); } return 0; } public int i(String tag, String msg, Throwable tr) { if (logLevel <= INFO) { out.println(tag + " : " + msg); tr.printStackTrace(out); } return 0; } public int w(String tag, String msg) { if (logLevel <= WARN) { out.println(tag + " : " + msg); } return 0; } public int w(String tag, String msg, Throwable tr) { if (logLevel <= WARN) { out.println(tag + " : " + msg); tr.printStackTrace(out); } return 0; } //public native boolean isLoggable(java.lang.String tag, int level); public int w(String tag, Throwable tr) { return Log.w(tag, tr); } public int e(String tag, String msg) { if (logLevel <= ERROR) { out.println(tag + " : " + msg); } return 0; } public int e(String tag, String msg, Throwable tr) { if (logLevel <= ERROR) { out.println(tag + " : " + msg); tr.printStackTrace(out); } return 0; } public String getStackTraceString(Throwable tr) { final Writer result = new StringWriter(); final PrintWriter printWriter = new PrintWriter(result); // If the exception was thrown in a background thread inside // AsyncTask, then the actual exception can be found with getCause Throwable cause = tr; while (cause != null) { cause.printStackTrace(printWriter); cause = cause.getCause(); } final String stacktraceAsString = result.toString(); printWriter.close(); return stacktraceAsString; } //public native int println(int priority, java.lang.String tag, java.lang.String msg); }
Dynamically defined), space efficient event logging to help instrument code for large scale stability and performance monitoring.
//package android.util; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Collection; public class EventLog { // Value types public static final byte INT = 0; public static final byte LONG = 1; public static final byte STRING = 2; public static final byte LIST = 3; public static final class List { private Object[] mItems; public final Object getItem(int pos) { return mItems[pos]; } public final byte getNumItems() { return (byte) mItems.length; } public List(Object... items) throws IllegalArgumentException { if (items.length > Byte.MAX_VALUE) { throw new IllegalArgumentException( "A List must have fewer than " + Byte.MAX_VALUE + " items in it."); } for (int i = 0; i < items.length; i++) { final Object item = items[i]; if (item == null) { // Would be nice to be able to write null strings... items[i] = ""; } else if (!(item instanceof List || item instanceof String || item instanceof Integer || item instanceof Long)) { throw new IllegalArgumentException( "Attempt to create a List with illegal item type."); } } this.mItems = items; } } public static final class Event { private final ByteBuffer mBuffer; // Layout of event log entry received from kernel. private static final int LENGTH_OFFSET = 0; private static final int PROCESS_OFFSET = 4; private static final int THREAD_OFFSET = 8; private static final int SECONDS_OFFSET = 12; private static final int NANOSECONDS_OFFSET = 16; private static final int PAYLOAD_START = 20; private static final int TAG_OFFSET = 20; private static final int DATA_START = 24; /** @param data containing event, read from the system */ public Event(byte[] data) { mBuffer = ByteBuffer.wrap(data); mBuffer.order(ByteOrder.nativeOrder()); } public int getProcessId() { return mBuffer.getInt(PROCESS_OFFSET); } public int getThreadId() { return mBuffer.getInt(THREAD_OFFSET); } public long getTimeNanos() { return mBuffer.getInt(SECONDS_OFFSET) * 1000000000l + mBuffer.getInt(NANOSECONDS_OFFSET); } public int getTag() { return mBuffer.getInt(TAG_OFFSET); } /** @return one of Integer, Long, String, or List. */ public synchronized Object getData() { mBuffer.limit(PAYLOAD_START + mBuffer.getShort(LENGTH_OFFSET)); mBuffer.position(DATA_START); // Just after the tag. return decodeObject(); } public byte[] getRawData() { return mBuffer.array(); } /** @return the loggable item at the current position in mBuffer. */ private Object decodeObject() { if (mBuffer.remaining() < 1) return null; switch (mBuffer.get()) { case INT: if (mBuffer.remaining() < 4) return null; return (Integer) mBuffer.getInt(); case LONG: if (mBuffer.remaining() < 8) return null; return (Long) mBuffer.getLong(); case STRING: try { if (mBuffer.remaining() < 4) return null; int length = mBuffer.getInt(); if (length < 0 || mBuffer.remaining() < length) return null; int start = mBuffer.position(); mBuffer.position(start + length); return new String(mBuffer.array(), start, length, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); // UTF-8 is guaranteed. } case LIST: if (mBuffer.remaining() < 1) return null; int length = mBuffer.get(); if (length < 0) return null; Object[] array = new Object[length]; for (int i = 0; i < length; ++i) { array[i] = decodeObject(); if (array[i] == null) return null; } return new List(array); default: return null; } } } // We assume that the native methods deal with any concurrency issues. public static native int writeEvent(int tag, int value); public static native int writeEvent(int tag, long value); public static native int writeEvent(int tag, String str); public static native int writeEvent(int tag, List list); public static int writeEvent(int tag, Object... list) { return writeEvent(tag, new List(list)); } public static native void readEvents(int[] tags, Collection<Event> output) throws IOException; public static native void readEvents(String path, Collection<Event> output) throws IOException; }
Write Exception Stack to Log
//package org.alldroid.forum.utils; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import android.util.Log; public class ExceptionHelper { public static void WriteStack ( String tag, Exception ex ) { final Writer result = new StringWriter (); final PrintWriter printWriter = new PrintWriter ( result ); ex.printStackTrace ( printWriter ); String stacktrace = result.toString (); printWriter.close (); Log.e ( tag, stacktrace ); } }
Logger and Logger Listener
//package at.abraxas.amarino.log; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import android.util.Log; public class Logger { public static boolean enabled = true; public static final String KEY_IS_LOG_ENABLED = "is_log_enabled"; private static final boolean DEBUG = true; private static final String TAG = "AmarinoLogger"; private static final int MAX_LOG_ENTRIES = 200; private static ArrayList<LogListener> listeners = new ArrayList<LogListener>(); private static List<String> log = Collections.synchronizedList(new LinkedList<String>()); private static int logSize = 0; public static void d(String tag, String msg){ String text = tag + ": " + msg; if (DEBUG) Log.d(TAG, text); if (enabled) add(text); } public static void d(String msg){ if (DEBUG) Log.d(TAG, msg); if (enabled) add(msg); } private static void add(String msg){ synchronized (log){ if (logSize < MAX_LOG_ENTRIES){ logSize++; } else { // we don't check if elements are present, since we trust logSize log.remove(0); //log.removeFirst(); } log.add(msg); } notifyListeners(msg.toString()); } public static synchronized void clear(){ logSize = 0; log.clear(); } public static String getLog(){ StringBuilder sb = new StringBuilder(); synchronized(log){ ListIterator<String> iter = log.listIterator(); while (iter.hasNext()){ sb.append(iter.next()); sb.append("\n"); } } return sb.toString(); } public static synchronized void registerLogListener(LogListener listener) { if (!listeners.contains(listener)) listeners.add(listener); } public static synchronized void unregisterLogListener(LogListener listener) { listeners.remove(listener); } private static void notifyListeners(final String lastAddedMsg){ if (listeners != null){ for (LogListener ll : listeners) ll.logChanged(lastAddedMsg); } } } interface LogListener { public void logChanged(String lastAddedMsg); }
Log Exception trace
class Log { public static final String TAG = "tag"; public static void debug(String tag, String content) { StackTraceElement[] trace = new Throwable().getStackTrace(); String msg = ""; if (trace.length >= 1) { StackTraceElement elt = trace[1]; msg = "[" + elt.getFileName() + " Line:" + elt.getLineNumber() + "] " + elt.getMethodName() + " " + content; android.util.Log.i(tag, msg); } else { android.util.Log.i(tag, msg); } } public static void error(String tag, String content) { StackTraceElement[] trace = new Throwable().getStackTrace(); String msg = ""; if (trace.length >= 1) { StackTraceElement elt = trace[1]; msg = "[" + elt.getFileName() + " Line:" + elt.getLineNumber() + "] " + elt.getMethodName() + " " + content; android.util.Log.e(tag, msg); } else { android.util.Log.e(tag, msg); } } }
Log a list of objects
//package org.expressme.wireless.game; import android.util.Log; class Main { private static final String TAG_GAME = "GAME"; public static void log(Object... objs) { if (objs.length == 0) { Log.i(TAG_GAME, ""); return; } if (objs.length == 1) { Object o = objs[0]; if (o == null) { Log.i(TAG_GAME, "(null)"); } else { String s = o.toString(); int n = s.indexOf('.'); Log.i(n == (-1) ? TAG_GAME : s.substring(0, n), s); } return; } StringBuilder sb = new StringBuilder(128); for (Object o : objs) { sb.append(o == null ? "(null)" : o.toString()); } String s = sb.toString(); int n = s.indexOf('.'); Log.i(n == (-1) ? TAG_GAME : s.substring(0, n), s); } }
Utility log tool
import java.util.Hashtable; import android.util.Config; import android.util.Log; public class MyLogger { private static boolean sIsLoggerEnable = Config.DEBUG; private final static String LOG_TAG = "[SaveDataFlow]"; private static Hashtable<String, MyLogger> sLoggerTable; static { sLoggerTable = new Hashtable<String, MyLogger>(); if (Config.DEBUG) sIsLoggerEnable = true; else sIsLoggerEnable = false; } private String mClassName; public static MyLogger getLogger(String className) { MyLogger classLogger = (MyLogger) sLoggerTable.get(className); if (classLogger == null) { classLogger = new MyLogger(className); sLoggerTable.put(className, classLogger); } return classLogger; } private MyLogger(String name) { mClassName = name; } public void v(String log) { if (sIsLoggerEnable) { Log.v(LOG_TAG, "{Thread:" + Thread.currentThread().getName() + "}" + "[" + mClassName + ":] " + log); } } public void d(String log) { if (sIsLoggerEnable) { Log.d(LOG_TAG, "{Thread:" + Thread.currentThread().getName() + "}" + "[" + mClassName + ":] " + log); } } public void i(String log) { if (sIsLoggerEnable) { Log.i(LOG_TAG, "{Thread:" + Thread.currentThread().getName() + "}" + "[" + mClassName + ":] " + log); } } public void i(String log, Throwable tr) { if (sIsLoggerEnable) { Log.i(LOG_TAG, "{Thread:" + Thread.currentThread().getName() + "}" + "[" + mClassName + ":] " + log + "\n" + Log.getStackTraceString(tr)); } } public void w(String log) { if (sIsLoggerEnable) { Log.w(LOG_TAG, "{Thread:" + Thread.currentThread().getName() + "}" + "[" + mClassName + ":] " + log); } } public void w(String log, Throwable tr) { if (sIsLoggerEnable) { Log.w(LOG_TAG, "{Thread:" + Thread.currentThread().getName() + "}" + "[" + mClassName + ":] " + log + "\n" + Log.getStackTraceString(tr)); } } public void e(String log) { Log.e(LOG_TAG, "{Thread:" + Thread.currentThread().getName() + "}" + "[" + mClassName + ":] " + log); } public void e(String log, Throwable tr) { Log.e(LOG_TAG, "{Thread:" + Thread.currentThread().getName() + "}" + "[" + mClassName + ":] " + log + "\n" + Log.getStackTraceString(tr)); } }
Debug Util
//package org.anddev.andengine.util; import android.util.Log; class Debug { private static String sDebugTag = "DEBUGTAG"; private static DebugLevel sDebugLevel = DebugLevel.VERBOSE; public static String getDebugTag() { return Debug.sDebugTag; } public static void setDebugTag(final String pDebugTag) { Debug.sDebugTag = pDebugTag; } public static DebugLevel getDebugLevel() { return Debug.sDebugLevel; } public static void setDebugLevel(final DebugLevel pDebugLevel) { if(pDebugLevel == null) { throw new IllegalArgumentException("pDebugLevel must not be null!"); } Debug.sDebugLevel = pDebugLevel; } public static void v(final String pMessage) { Debug.v(pMessage, null); } public static void v(final String pMessage, final Throwable pThrowable) { if(sDebugLevel.isSameOrLessThan(DebugLevel.VERBOSE)) { Log.v(sDebugTag, pMessage, pThrowable); } } public static void d(final String pMessage) { Debug.d(pMessage, null); } public static void d(final String pMessage, final Throwable pThrowable) { if(sDebugLevel.isSameOrLessThan(DebugLevel.DEBUG)) { Log.d(sDebugTag, pMessage, pThrowable); } } public static void i(final String pMessage) { Debug.i(pMessage, null); } public static void i(final String pMessage, final Throwable pThrowable) { if(sDebugLevel.isSameOrLessThan(DebugLevel.INFO)) { Log.i(sDebugTag, pMessage, pThrowable); } } public static void w(final String pMessage) { Debug.w(pMessage, null); } public static void w(final Throwable pThrowable) { Debug.w("", pThrowable); } public static void w(final String pMessage, final Throwable pThrowable) { if(sDebugLevel.isSameOrLessThan(DebugLevel.WARNING)) { if(pThrowable == null) { Log.w(sDebugTag, pMessage, new Exception()); } else { Log.w(sDebugTag, pMessage, pThrowable); } } } public static void e(final String pMessage) { Debug.e(pMessage, null); } public static void e(final Throwable pThrowable) { Debug.e(sDebugTag, pThrowable); } public static void e(final String pMessage, final Throwable pThrowable) { if(sDebugLevel.isSameOrLessThan(DebugLevel.ERROR)) { if(pThrowable == null) { Log.e(sDebugTag, pMessage, new Exception()); } else { Log.e(sDebugTag, pMessage, pThrowable); } } } // // Inner and Anonymous Classes // public static enum DebugLevel implements Comparable<DebugLevel> { NONE, ERROR, WARNING, INFO, DEBUG, VERBOSE; public static DebugLevel ALL = DebugLevel.VERBOSE; private boolean isSameOrLessThan(final DebugLevel pDebugLevel) { return this.compareTo(pDebugLevel) >= 0; } } }