Log与logcat

1. 概述

应用开发与调试中,可以使用Log增加日志打印;然后通过logcat观察&分析日志,定位问题。


2. Log调用

2.1 方法

Log的调用非常简单,通常包括两个步骤:

  • 定义TAG;
  • Log.e(), w(), i(), d(), v()打印日志

当然,第一步定义TAG不是必须的,但是惯用法。通常一个Activity或Service会定义这个类的一个TAG,从而和其他的组件区分开来;然后在这个组件直接Log(TAG, msg)调用。


2.2 示例

public class MainActivity extends ActionBarActivity {

	private static final String TAG = "MyActivity";
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, new PlaceholderFragment())
                    .commit();
        }
    
        Log.d(TAG, "onCreate()");
    }

2.3 源码

Log的源码如下,包括了前面提到的使用方法:

/**
 * API for sending log output.
 *
 * <p>Generally, use the Log.v() Log.d() Log.i() Log.w() and Log.e()
 * methods.
 *
 * <p>The order in terms of verbosity, from least to most is
 * ERROR, WARN, INFO, DEBUG, VERBOSE.  Verbose should never be compiled
 * into an application except during development.  Debug logs are compiled
 * in but stripped at runtime.  Error, warning and info logs are always kept.
 *
 * <p><b>Tip:</b> A good convention is to declare a <code>TAG</code> constant
 * in your class:
 *
 * <pre>private static final String TAG = "MyActivity";</pre>
 *
 * and use that in subsequent calls to the log methods.
 * </p>
 *
 * <p><b>Tip:</b> Don't forget that when you make a call like
 * <pre>Log.v(TAG, "index=" + i);</pre>
 * that when you're building the string to pass into Log.d, the compiler uses a
 * StringBuilder and at least three allocations occur: the StringBuilder
 * itself, the buffer, and the String object.  Realistically, there is also
 * another buffer allocation and copy, and even more pressure on the gc.
 * That means that if your log message is filtered out, you might be doing
 * significant work and incurring significant overhead.
 */
public final class Log {

2.4 注意事项

Log的调用应该谨慎,不能使用泛滥。一方面,这样不利于定位,大量的无价值的日志会淹没真正有价值的信息,降低定位问题的效率;另一方面,大量的日志会影响程序的运行效率。而且对于手机设备来讲,会影响电池的续航能力(如前面源码中的描述)。


3. logcat

logcat用于捕获(不限于)Log输出的日志信息,包括adb logcat和Eclipse (ADT)的logcat窗口两种方法。

3.1 adb logcat

直接通过adb logcat查看日志,示例:

flying-bird@flyingbird:~/software/android/adt-bundle-linux-x86-20140321/sdk/platform-tools$ ./adb logcat
--------- beginning of /dev/log/system
I/Vold    (   78): Vold 2.1 (the revenge) firing up
D/Vold    (   78): Volume sdcard state changing -1 (Initializing) -> 0 (No-Media)
W/DirectVolume(   78): Kernel block uevent 'PARTN' 1 pendingparts 0
D/Vold    (   78): Volume sdcard state changing 0 (No-Media) -> 2 (Pending)
W/DirectVolume(   78): Kernel block uevent 'PARTN' 1, 1 minor 1
D/Vold    (   78): Volume sdcard state changing 2 (Pending) -> 1 (Idle-Unmounted)
E/NetlinkEvent(   78): NetlinkEvent::FindParam(): Parameter 'SWITCH_NAME' not found
E/NetlinkEvent(   78): NetlinkEvent::FindParam(): Parameter 'SWITCH_STATE' not found
W/Vold    (   78): Switch /devices/virtual/switch/usb_mass_storage event missing name/state info
E/NetlinkEvent(   78): NetlinkEvent::FindParam(): Parameter 'SWITCH_NAME' not found
E/NetlinkEvent(   78): NetlinkEvent::FindParam(): Parameter 'SWITCH_STATE' not found
W/Vold    (   78): Switch /devices/virtual/switch/usb_mass_storage event missing name/state info
W/Vold    (   78): open sys/devices/platform/msm_hsusb/gadget/lun1/file fail:(No such file or directory)
D/VoldCmdListener(   78): volume list
D/VoldCmdListener(   78): share status ums
D/VoldCmdListener(   78): share status ums
D/VoldCmdListener(   78): volume mount /mnt/sdcard
E/DirectVolume(   78): getDeviceNodes i 0 j 0 1
E/Vold    (   78): /dev/block/vold/179:1 being considered for volume sdcard
D/Vold    (   78): Volume sdcard state changing 1 (Idle-Unmounted) -> 3 (Checking)
I/Vold    (   78): Filesystem check completed OK
I/Vold    (   78): Device /dev/block/vold/179:1, target /mnt/sdcard mounted @ /mnt/secure/staging
D/Vold    (   78): Volume sdcard state changing 3 (Checking) -> 4 (Mounted)
D/VoldCmdListener(   78): asec list
E/NetlinkEvent(   78): NetlinkEvent::FindParam(): Parameter 'SWITCH_NAME' not found
E/NetlinkEvent(   78): NetlinkEvent::FindParam(): Parameter 'SWITCH_STATE' not found
W/Vold    (   78): Switch /devices/virtual/switch/usb_mass_storage event missing name/state info
E/NetlinkEvent(   78): NetlinkEvent::FindParam(): Parameter 'SWITCH_NAME' not found

可以看到简单的logcat会输出大量的日志信息。手机厂商通常会预置一些app,消费者拿到手机之后,也会安装一些。由于某些app会滥用Log,因此会导致大量的日志打印出来。


为此,需要对logcat的结果进行过滤。

3.2 adb logcat --help

最简单地,我们直接查阅logcat的帮助信息:

flying-bird@flyingbird:~/software/android/adt-bundle-linux-x86-20140321/sdk/platform-tools$ ./adb logcat --help
Usage: logcat [options] [filterspecs]
options include:
  -s              Set default filter to silent.
                  Like specifying filterspec '*:s'
  -f <filename>   Log to file. Default to stdout
  -r [<kbytes>]   Rotate log every kbytes. (16 if unspecified). Requires -f
  -n <count>      Sets max number of rotated logs to <count>, default 4
  -v <format>     Sets the log print format, where <format> is one of:

                  brief process tag thread raw time threadtime long

  -c              clear (flush) the entire log and exit
  -d              dump the log and then exit (don't block)
  -t <count>      print only the most recent <count> lines (implies -d)
  -g              get the size of the log's ring buffer and exit
  -b <buffer>     request alternate ring buffer
                  ('main' (default), 'radio', 'events')
  -B              output the log in binary
filterspecs are a series of 
  <tag>[:priority]

where <tag> is a log component tag (or * for all) and priority is:
  V    Verbose
  D    Debug
  I    Info
  W    Warn
  E    Error
  F    Fatal
  S    Silent (supress all output)

'*' means '*:d' and <tag> by itself means <tag>:v

If not specified on the commandline, filterspec is set from ANDROID_LOG_TAGS.
If no filterspec is found, filter defaults to '*:I'

If not specified with -v, format is set from ANDROID_PRINTF_LOG
or defaults to "brief"

flying-bird@flyingbird:~/software/android/adt-bundle-linux-x86-20140321/sdk/platform-tools$ 

或者从Android官网查阅详细信息。由于众所周知的原因,频繁进入developer.android.com是很费劲的,因此最好把Android SDK docs下载一份到本地,具体请参考 Ubuntu下面搭建Android应用开发环境。示例:


3.3 adb logcat使用示例

只显示特定的Activity的debug及以上的日志:

flying-bird@flyingbird:~/software/android/adt-bundle-linux-x86-20140321/sdk/platform-tools$ ./adb logcat MyActivity:d *:S
--------- beginning of /dev/log/system
--------- beginning of /dev/log/main
D/MyActivity( 1939): onCreate()
D/MyActivity( 1939): onResume()
D/MyActivity( 1939): onStop()

如果显示MyActivity的所有日志,则可以直接adb logcat MyActivity *:S

flying-bird@flyingbird:~/software/android/adt-bundle-linux-x86-20140321/sdk/platform-tools$ ./adb logcat MyActivity *:S
--------- beginning of /dev/log/system
--------- beginning of /dev/log/main
D/MyActivity( 1939): onCreate()
D/MyActivity( 1939): onResume()
D/MyActivity( 1939): onStop()

或者

flying-bird@flyingbird:~/software/android/adt-bundle-linux-x86-20140321/sdk/platform-tools$ ./adb logcat -s MyActivity
--------- beginning of /dev/log/system
--------- beginning of /dev/log/main
D/MyActivity( 1939): onCreate()
D/MyActivity( 1939): onResume()
D/MyActivity( 1939): onStop()

如果日志非常多,希望重定向到文件中,事后分析,也是可以的,只需要> mylog即可:


其他几种常用法:

a. 每条日志前面增加时间戳:-v time

flying-bird@flyingbird:~/software/android/adt-bundle-linux-x86-20140321/sdk/platform-tools$ ./adb logcat -s -v time MyActivity
--------- beginning of /dev/log/system
--------- beginning of /dev/log/main
06-05 19:13:57.089 D/MyActivity( 1939): onCreate()
06-05 19:13:57.099 D/MyActivity( 1939): onResume()
06-05 19:14:00.259 D/MyActivity( 1939): onStop()

b. 取完日志之后就退出adb进程:-d

flying-bird@flyingbird:~/software/android/adt-bundle-linux-x86-20140321/sdk/platform-tools$ ./adb logcat -s -v time -d MyActivity
--------- beginning of /dev/log/system
--------- beginning of /dev/log/main
06-05 19:13:57.089 D/MyActivity( 1939): onCreate()
06-05 19:13:57.099 D/MyActivity( 1939): onResume()
06-05 19:14:00.259 D/MyActivity( 1939): onStop()
flying-bird@flyingbird:~/software/android/adt-bundle-linux-x86-20140321/sdk/platform-tools$ 

c. 日志本身是缓存的,如果要清除历史日志,则使用-c,然后再用前面的命令:

flying-bird@flyingbird:~/software/android/adt-bundle-linux-x86-20140321/sdk/platform-tools$ ./adb logcat -c
flying-bird@flyingbird:~/software/android/adt-bundle-linux-x86-20140321/sdk/platform-tools$ ./adb logcat -s -v time -d MyActivity
--------- beginning of /dev/log/main
flying-bird@flyingbird:~/software/android/adt-bundle-linux-x86-20140321/sdk/platform-tools$ ./adb logcat -s -v time MyActivity
--------- beginning of /dev/log/main
06-05 19:17:07.769 D/MyActivity( 1939): onCreate()
06-05 19:17:07.769 D/MyActivity( 1939): onResume()
06-05 19:17:16.299 D/MyActivity( 1939): onStop()


3.4 Eclipse Logcat View



几种常用的过滤方法:

1. 指定某个Activity的日志:tag:MyActivity

2. 某个app:app:com.example.helloworld

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值