0

[android] Change the recommended log tag format to "cr_foo"

This is to ensure that log tags are not elided when retrieving
logcat output from crash reports. The log function has been
modified to make the transition easier and avoid specifying
the prefix everywhere.

This patch also moves some eliding testing from instrumentation
tests to junit tests, and adds a test to ensure that the new
tag format is not elided.

BUG=533072

Review URL: https://codereview.chromium.org/1354723004

Cr-Commit-Position: refs/heads/master@{#349733}
This commit is contained in:
dgn
2015-09-18 12:20:51 -07:00
committed by Commit bot
parent 252494591a
commit 38736db931
7 changed files with 336 additions and 246 deletions
PRESUBMIT.pyPRESUBMIT_test.py
base/android
java
src
org
chromium
junit
src
org
chromium
chrome/android
javatests
src
org
chromium
junit
src
org
chromium
docs

@ -1353,8 +1353,7 @@ def _CheckAndroidToastUsage(input_api, output_api):
def _CheckAndroidCrLogUsage(input_api, output_api):
"""Checks that new logs using org.chromium.base.Log:
- Are using 'TAG' as variable name for the tags (warn)
- Are using the suggested name format for the tags: "cr.<PackageTag>" (warn)
- Are using a tag that is shorter than 23 characters (error)
- Are using a tag that is shorter than 20 characters (error)
"""
cr_log_import_pattern = input_api.re.compile(
r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
@ -1365,9 +1364,8 @@ def _CheckAndroidCrLogUsage(input_api, output_api):
# Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
log_decl_pattern = input_api.re.compile(
r'^\s*private static final String TAG = "(?P<name>(.*)")',
r'^\s*private static final String TAG = "(?P<name>(.*))";',
input_api.re.MULTILINE)
log_name_pattern = input_api.re.compile(r'^cr[.\w]*')
REF_MSG = ('See docs/android_logging.md '
'or contact dgn@chromium.org for more info.')
@ -1376,6 +1374,7 @@ def _CheckAndroidCrLogUsage(input_api, output_api):
tag_decl_errors = []
tag_length_errors = []
tag_errors = []
tag_with_dot_errors = []
util_log_errors = []
for f in input_api.AffectedSourceFiles(sources):
@ -1407,23 +1406,26 @@ def _CheckAndroidCrLogUsage(input_api, output_api):
if has_modified_logs:
# Make sure the tag is using the "cr" prefix and is not too long
match = log_decl_pattern.search(file_content)
tag_name = match.group('name') if match else ''
if not log_name_pattern.search(tag_name ):
tag_name = match.group('name') if match else None
if not tag_name:
tag_decl_errors.append(f.LocalPath())
if len(tag_name) > 23:
elif len(tag_name) > 20:
tag_length_errors.append(f.LocalPath())
elif '.' in tag_name:
tag_with_dot_errors.append(f.LocalPath())
results = []
if tag_decl_errors:
results.append(output_api.PresubmitPromptWarning(
'Please define your tags using the suggested format: .\n'
'"private static final String TAG = "cr.<package tag>".\n' + REF_MSG,
'"private static final String TAG = "<package tag>".\n'
'They will be prepended with "cr_" automatically.\n' + REF_MSG,
tag_decl_errors))
if tag_length_errors:
results.append(output_api.PresubmitError(
'The tag length is restricted by the system to be at most '
'23 characters.\n' + REF_MSG,
'20 characters.\n' + REF_MSG,
tag_length_errors))
if tag_errors:
@ -1436,6 +1438,11 @@ def _CheckAndroidCrLogUsage(input_api, output_api):
'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
util_log_errors))
if tag_with_dot_errors:
results.append(output_api.PresubmitPromptWarning(
'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
tag_with_dot_errors))
return results

@ -463,7 +463,7 @@ class CheckAddedDepsHaveTetsApprovalsTest(unittest.TestCase):
'"+chrome/plugin/chrome_content_plugin_client.h",',
'"+chrome/utility/chrome_content_utility_client.h",',
'"+chromeos/chromeos_paths.h",',
'"+components/crash",',
'"+components/crash/content",',
'"+components/nacl/common",',
'"+content/public/browser/render_process_host.h",',
'"+jni/fooblat.h",',
@ -840,32 +840,38 @@ class LogUsageTest(unittest.TestCase):
]),
MockAffectedFile('IsInBasePackage.java', [
'package org.chromium.base;',
'private static final String TAG = "cr.Foo";',
'private static final String TAG = "cr_Foo";',
'Log.d(TAG, "foo");',
]),
MockAffectedFile('IsInBasePackageButImportsLog.java', [
'package org.chromium.base;',
'import android.util.Log;',
'private static final String TAG = "cr.Foo";',
'private static final String TAG = "cr_Foo";',
'Log.d(TAG, "foo");',
]),
MockAffectedFile('HasBothLog.java', [
'import org.chromium.base.Log;',
'some random stuff',
'private static final String TAG = "cr.Foo";',
'private static final String TAG = "cr_Foo";',
'Log.d(TAG, "foo");',
'android.util.Log.d("TAG", "foo");',
]),
MockAffectedFile('HasCorrectTag.java', [
'import org.chromium.base.Log;',
'some random stuff',
'private static final String TAG = "cr_Foo";',
'Log.d(TAG, "foo");',
]),
MockAffectedFile('HasOldTag.java', [
'import org.chromium.base.Log;',
'some random stuff',
'private static final String TAG = "cr.Foo";',
'Log.d(TAG, "foo");',
]),
MockAffectedFile('HasShortCorrectTag.java', [
MockAffectedFile('HasDottedTag.java', [
'import org.chromium.base.Log;',
'some random stuff',
'private static final String TAG = "cr";',
'private static final String TAG = "cr_foo.bar";',
'Log.d(TAG, "foo");',
]),
MockAffectedFile('HasNoTagDecl.java', [
@ -875,17 +881,17 @@ class LogUsageTest(unittest.TestCase):
]),
MockAffectedFile('HasIncorrectTagDecl.java', [
'import org.chromium.base.Log;',
'private static final String TAHG = "cr.Foo";',
'private static final String TAHG = "cr_Foo";',
'some random stuff',
'Log.d(TAG, "foo");',
]),
MockAffectedFile('HasInlineTag.java', [
'import org.chromium.base.Log;',
'some random stuff',
'private static final String TAG = "cr.Foo";',
'private static final String TAG = "cr_Foo";',
'Log.d("TAG", "foo");',
]),
MockAffectedFile('HasIncorrectTag.java', [
MockAffectedFile('HasUnprefixedTag.java', [
'import org.chromium.base.Log;',
'some random stuff',
'private static final String TAG = "rubbish";',
@ -894,7 +900,7 @@ class LogUsageTest(unittest.TestCase):
MockAffectedFile('HasTooLongTag.java', [
'import org.chromium.base.Log;',
'some random stuff',
'private static final String TAG = "cr.24_charachers_long___";',
'private static final String TAG = "21_charachers_long___";',
'Log.d(TAG, "foo");',
]),
]
@ -902,27 +908,42 @@ class LogUsageTest(unittest.TestCase):
msgs = PRESUBMIT._CheckAndroidCrLogUsage(
mock_input_api, mock_output_api)
self.assertEqual(4, len(msgs))
self.assertEqual(5, len(msgs),
'Expected %d items, found %d: %s' % (5, len(msgs), msgs))
# Declaration format
self.assertEqual(3, len(msgs[0].items))
nb = len(msgs[0].items)
self.assertEqual(2, nb,
'Expected %d items, found %d: %s' % (2, nb, msgs[0].items))
self.assertTrue('HasNoTagDecl.java' in msgs[0].items)
self.assertTrue('HasIncorrectTagDecl.java' in msgs[0].items)
self.assertTrue('HasIncorrectTag.java' in msgs[0].items)
# Tag length
self.assertEqual(1, len(msgs[1].items))
nb = len(msgs[1].items)
self.assertEqual(1, nb,
'Expected %d items, found %d: %s' % (1, nb, msgs[1].items))
self.assertTrue('HasTooLongTag.java' in msgs[1].items)
# Tag must be a variable named TAG
self.assertEqual(1, len(msgs[2].items))
nb = len(msgs[2].items)
self.assertEqual(1, nb,
'Expected %d items, found %d: %s' % (1, nb, msgs[2].items))
self.assertTrue('HasInlineTag.java:4' in msgs[2].items)
# Util Log usage
self.assertEqual(2, len(msgs[3].items))
nb = len(msgs[3].items)
self.assertEqual(2, nb,
'Expected %d items, found %d: %s' % (2, nb, msgs[3].items))
self.assertTrue('HasAndroidLog.java:3' in msgs[3].items)
self.assertTrue('IsInBasePackageButImportsLog.java:4' in msgs[3].items)
# Tag must not contain
nb = len(msgs[4].items)
self.assertEqual(2, nb,
'Expected %d items, found %d: %s' % (2, nb, msgs[4].items))
self.assertTrue('HasDottedTag.java' in msgs[4].items)
self.assertTrue('HasOldTag.java' in msgs[4].items)
if __name__ == '__main__':
unittest.main()

@ -39,6 +39,9 @@ public class Log {
/** Convenience property, same as {@link android.util.Log#WARN}. */
public static final int WARN = android.util.Log.WARN;
private static final String sTagPrefix = "cr_";
private static final String sDeprecatedTagPrefix = "cr.";
private Log() {
// Static only access
}
@ -52,6 +55,24 @@ public class Log {
return messageTemplate;
}
/**
* Returns a normalized tag that will be in the form: "cr_foo". This function is called by the
* various Log overrides. If using {@link #isLoggable(String, int)}, you might want to call it
* to get the tag that will actually be used.
* @see #sTagPrefix
*/
public static String normalizeTag(String tag) {
if (tag.startsWith(sTagPrefix)) return tag;
// TODO(dgn) simplify this once 'cr.' is out of the repo (http://crbug.com/533072)
int unprefixedTagStart = 0;
if (tag.startsWith(sDeprecatedTagPrefix)) {
unprefixedTagStart = sDeprecatedTagPrefix.length();
}
return sTagPrefix + tag.substring(unprefixedTagStart, tag.length());
}
/**
* Returns a formatted log message, using the supplied format and arguments.
* The message will be prepended with the filename and line number of the call.
@ -77,7 +98,8 @@ public class Log {
* than 7 parameters, consider building your log message using a function annotated with
* {@link RemovableInRelease}.
*
* @param tag Used to identify the source of a log message.
* @param tag Used to identify the source of a log message. Might be modified in the output
* (see {@link #normalizeTag(String)})
* @param messageTemplate The message you would like logged. It is to be specified as a format
* string.
* @param args Arguments referenced by the format specifiers in the format string. If the last
@ -87,9 +109,9 @@ public class Log {
String message = formatLogWithStack(messageTemplate, args);
Throwable tr = getThrowableToLog(args);
if (tr != null) {
android.util.Log.v(tag, message, tr);
android.util.Log.v(normalizeTag(tag), message, tr);
} else {
android.util.Log.v(tag, message);
android.util.Log.v(normalizeTag(tag), message);
}
}
@ -161,7 +183,8 @@ public class Log {
* than 7 parameters, consider building your log message using a function annotated with
* {@link RemovableInRelease}.
*
* @param tag Used to identify the source of a log message.
* @param tag Used to identify the source of a log message. Might be modified in the output
* (see {@link #normalizeTag(String)})
* @param messageTemplate The message you would like logged. It is to be specified as a format
* string.
* @param args Arguments referenced by the format specifiers in the format string. If the last
@ -171,9 +194,9 @@ public class Log {
String message = formatLogWithStack(messageTemplate, args);
Throwable tr = getThrowableToLog(args);
if (tr != null) {
android.util.Log.d(tag, message, tr);
android.util.Log.d(normalizeTag(tag), message, tr);
} else {
android.util.Log.d(tag, message);
android.util.Log.d(normalizeTag(tag), message);
}
}
@ -239,7 +262,8 @@ public class Log {
/**
* Sends an {@link android.util.Log#INFO} log message.
*
* @param tag Used to identify the source of a log message.
* @param tag Used to identify the source of a log message. Might be modified in the output
* (see {@link #normalizeTag(String)})
* @param messageTemplate The message you would like logged. It is to be specified as a format
* string.
* @param args Arguments referenced by the format specifiers in the format string. If the last
@ -250,16 +274,17 @@ public class Log {
String message = formatLog(messageTemplate, args);
Throwable tr = getThrowableToLog(args);
if (tr != null) {
android.util.Log.i(tag, message, tr);
android.util.Log.i(normalizeTag(tag), message, tr);
} else {
android.util.Log.i(tag, message);
android.util.Log.i(normalizeTag(tag), message);
}
}
/**
* Sends a {@link android.util.Log#WARN} log message.
*
* @param tag Used to identify the source of a log message.
* @param tag Used to identify the source of a log message. Might be modified in the output
* (see {@link #normalizeTag(String)})
* @param messageTemplate The message you would like logged. It is to be specified as a format
* string.
* @param args Arguments referenced by the format specifiers in the format string. If the last
@ -270,16 +295,17 @@ public class Log {
String message = formatLog(messageTemplate, args);
Throwable tr = getThrowableToLog(args);
if (tr != null) {
android.util.Log.w(tag, message, tr);
android.util.Log.w(normalizeTag(tag), message, tr);
} else {
android.util.Log.w(tag, message);
android.util.Log.w(normalizeTag(tag), message);
}
}
/**
* Sends an {@link android.util.Log#ERROR} log message.
*
* @param tag Used to identify the source of a log message.
* @param tag Used to identify the source of a log message. Might be modified in the output
* (see {@link #normalizeTag(String)})
* @param messageTemplate The message you would like logged. It is to be specified as a format
* string.
* @param args Arguments referenced by the format specifiers in the format string. If the last
@ -290,9 +316,9 @@ public class Log {
String message = formatLog(messageTemplate, args);
Throwable tr = getThrowableToLog(args);
if (tr != null) {
android.util.Log.e(tag, message, tr);
android.util.Log.e(normalizeTag(tag), message, tr);
} else {
android.util.Log.e(tag, message);
android.util.Log.e(normalizeTag(tag), message);
}
}
@ -303,7 +329,8 @@ public class Log {
*
* @see android.util.Log#wtf(String, String, Throwable)
*
* @param tag Used to identify the source of a log message.
* @param tag Used to identify the source of a log message. Might be modified in the output
* (see {@link #normalizeTag(String)})
* @param messageTemplate The message you would like logged. It is to be specified as a format
* string.
* @param args Arguments referenced by the format specifiers in the format string. If the last
@ -314,9 +341,9 @@ public class Log {
String message = formatLog(messageTemplate, args);
Throwable tr = getThrowableToLog(args);
if (tr != null) {
android.util.Log.wtf(tag, message, tr);
android.util.Log.wtf(normalizeTag(tag), message, tr);
} else {
android.util.Log.wtf(tag, message);
android.util.Log.wtf(normalizeTag(tag), message);
}
}

@ -32,6 +32,14 @@ public class LogTest {
logs.get(0).msg.matches("\\[LogTest.java:\\d+\\].*"));
}
@Test
public void normalizeTagTest() {
assertEquals("cr_foo", Log.normalizeTag("cr.foo"));
assertEquals("cr_foo", Log.normalizeTag("cr_foo"));
assertEquals("cr_foo", Log.normalizeTag("foo"));
assertEquals("cr_ab_foo", Log.normalizeTag("ab_foo"));
}
/** Tests that exceptions provided to the log functions are properly recognized and printed. */
@Test
public void exceptionLoggingTest() {

@ -4,17 +4,10 @@
package org.chromium.chrome.browser.crash;
import static org.chromium.chrome.browser.crash.LogcatExtractionCallable.BEGIN_MICRODUMP;
import static org.chromium.chrome.browser.crash.LogcatExtractionCallable.END_MICRODUMP;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
import org.chromium.base.test.util.AdvancedMockContext;
@ -22,11 +15,7 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@ -36,192 +25,11 @@ import java.util.concurrent.atomic.AtomicInteger;
public class LogcatExtractionCallableTest extends CrashTestCase {
private File mCrashDir;
private static final int MAX_LINES = 5;
protected void setUp() throws Exception {
super.setUp();
mCrashDir = new CrashFileManager(mCacheDir).getCrashDirectory();
}
@SmallTest
public void testElideEmail() {
String original = "email me at someguy@mailservice.com";
String expected = "email me at XXX@EMAIL.ELIDED";
assertEquals(expected, LogcatExtractionCallable.elideEmail(original));
}
@SmallTest
public void testElideUrl() {
String original = "file bugs at crbug.com";
String expected = "file bugs at HTTP://WEBADDRESS.ELIDED";
assertEquals(expected, LogcatExtractionCallable.elideUrl(original));
}
@SmallTest
public void testElideUrl2() {
String original =
"exception at org.chromium.chrome.browser.crash.LogcatExtractionCallableTest";
assertEquals(original, LogcatExtractionCallable.elideUrl(original));
}
@SmallTest
public void testElideUrl3() {
String original = "file bugs at crbug.com or code.google.com";
String expected = "file bugs at HTTP://WEBADDRESS.ELIDED or HTTP://WEBADDRESS.ELIDED";
assertEquals(expected, LogcatExtractionCallable.elideUrl(original));
}
@SmallTest
public void testElideUrl4() {
String original = "test shorturl.com !!!";
String expected = "test HTTP://WEBADDRESS.ELIDED !!!";
assertEquals(expected, LogcatExtractionCallable.elideUrl(original));
}
@SmallTest
public void testElideUrl5() {
String original = "test just.the.perfect.len.url !!!";
String expected = "test HTTP://WEBADDRESS.ELIDED !!!";
assertEquals(expected, LogcatExtractionCallable.elideUrl(original));
}
@SmallTest
public void testElideUrl6() {
String original = "test a.very.very.very.very.very.long.url !!!";
String expected = "test HTTP://WEBADDRESS.ELIDED !!!";
assertEquals(expected, LogcatExtractionCallable.elideUrl(original));
}
@SmallTest
public void testElideUrl7() {
String original = " at android.content.Intent \n at java.util.ArrayList";
assertEquals(original, LogcatExtractionCallable.elideUrl(original));
}
@SmallTest
public void testElideIp() {
String original = "traceroute 127.0.0.1";
String expected = "traceroute 1.2.3.4";
assertEquals(expected, LogcatExtractionCallable.elideIp(original));
}
@SmallTest
public void testElideMac1() {
String original = "MAC: AB-AB-AB-AB-AB-AB";
String expected = "MAC: 01:23:45:67:89:AB";
assertEquals(expected, LogcatExtractionCallable.elideMac(original));
}
@SmallTest
public void testElideMac2() {
String original = "MAC: AB:AB:AB:AB:AB:AB";
String expected = "MAC: 01:23:45:67:89:AB";
assertEquals(expected, LogcatExtractionCallable.elideMac(original));
}
@SmallTest
public void testElideConsole() {
String original = "I/chromium(123): [INFO:CONSOLE(2)] hello!";
String expected = "I/chromium(123): [ELIDED:CONSOLE(0)] ELIDED CONSOLE MESSAGE";
assertEquals(expected, LogcatExtractionCallable.elideConsole(original));
}
@SmallTest
public void testLogcatEmpty() {
final String original = "";
List<String> expected = new LinkedList<>();
List<String> logcat = null;
try {
logcat = LogcatExtractionCallable.extractLogcatFromReader(
new BufferedReader(new StringReader(original)), MAX_LINES);
} catch (Exception e) {
fail(e.toString());
}
MoreAsserts.assertEquals(expected.toArray(), logcat.toArray());
}
@SmallTest
public void testLogcatWithoutBeginOrEnd_smallLogcat() {
final List<String> original = Arrays.asList("Line 1", "Line 2", "Line 3", "Line 4",
"Line 5");
assertLogcatLists(original, original);
}
@SmallTest
public void testLogcatWithoutBeginOrEnd_largeLogcat() {
final List<String> original = Arrays.asList("Line 1", "Line 2", "Line 3", "Line 4",
"Line 5", "Redundant Line 1", "Redundant Line 2");
final List<String> expected = Arrays.asList("Line 1", "Line 2", "Line 3", "Line 4",
"Line 5");
assertLogcatLists(expected, original);
}
@SmallTest
public void testLogcatBeginsWithBegin() {
final List<String> original = Arrays.asList(BEGIN_MICRODUMP, "a", "b", "c", "d", "e");
assertLogcatLists(new LinkedList<String>(), original);
}
@SmallTest
public void testLogcatWithBegin() {
final List<String> original = Arrays.asList("Line 1", "Line 2", BEGIN_MICRODUMP, "a",
"b", "c", "d", "e");
final List<String> expected = Arrays.asList("Line 1", "Line 2");
assertLogcatLists(expected, original);
}
@SmallTest
public void testLogcatWithEnd() {
final List<String> original = Arrays.asList("Line 1", "Line 2", END_MICRODUMP);
assertLogcatLists(new LinkedList<String>(), original);
}
@SmallTest
public void testLogcatWithBeginAndEnd_smallLogcat() {
final List<String> original = Arrays.asList("Line 1", "Line 2", BEGIN_MICRODUMP, "a", "b",
"c", "d", "e", END_MICRODUMP);
final List<String> expected = Arrays.asList("Line 1", "Line 2");
assertLogcatLists(expected, original);
}
@SmallTest
public void testLogcatWithBeginAndEnd_largeLogcat() {
final List<String> original = Arrays.asList("Line 1", "Line 2", BEGIN_MICRODUMP, "a", "b",
"c", "d", "e", END_MICRODUMP, "Line 3", "Line 4");
final List<String> expected = Arrays.asList("Line 1", "Line 2", "Line 3", "Line 4");
assertLogcatLists(expected, original);
}
@SmallTest
public void testLogcatWithEndAndBegin_smallLogcat() {
final List<String> original = Arrays.asList(END_MICRODUMP, "Line 1", "Line 2",
BEGIN_MICRODUMP, "a", "b", "c", "d", "e");
final List<String> expected = Arrays.asList("Line 1", "Line 2");
assertLogcatLists(expected, original);
}
@SmallTest
public void testLogcatWithEndAndBegin_largeLogcat() {
final List<String> original = Arrays.asList(END_MICRODUMP, "Line 1", "Line 2",
BEGIN_MICRODUMP, "a", "b", "c", "d", "e", END_MICRODUMP, "Line 3", "Line 4");
final List<String> expected = Arrays.asList("Line 1", "Line 2", "Line 3", "Line 4");
assertLogcatLists(expected, original);
}
private void assertLogcatLists(List<String> expected, List<String> original) {
List<String> actualLogcat = null;
String combinedLogcat = TextUtils.join("\n", original);
try {
//simulate a file reader to test whether the extraction process
//successfully strips microdump from logcat
actualLogcat = LogcatExtractionCallable.extractLogcatFromReader(
new BufferedReader(new StringReader(combinedLogcat)), MAX_LINES);
} catch (Exception e) {
fail(e.toString());
}
MoreAsserts.assertEquals(expected.toArray(), actualLogcat.toArray());
}
@MediumTest
public void testExtractToFile() {
final AtomicInteger numServiceStarts = new AtomicInteger(0);

@ -0,0 +1,218 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.crash;
import static org.chromium.chrome.browser.crash.LogcatExtractionCallable.BEGIN_MICRODUMP;
import static org.chromium.chrome.browser.crash.LogcatExtractionCallable.END_MICRODUMP;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import android.text.TextUtils;
import org.chromium.testing.local.LocalRobolectricTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import java.io.BufferedReader;
import java.io.StringReader;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
/**
* junit tests for {@link LogcatExtractionCallable}.
*/
@RunWith(LocalRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class LogcatExtractionCallableTest {
private static final int MAX_LINES = 5;
@Test
public void testElideEmail() {
String original = "email me at someguy@mailservice.com";
String expected = "email me at XXX@EMAIL.ELIDED";
assertEquals(expected, LogcatExtractionCallable.elideEmail(original));
}
@Test
public void testElideUrl() {
String original = "file bugs at crbug.com";
String expected = "file bugs at HTTP://WEBADDRESS.ELIDED";
assertEquals(expected, LogcatExtractionCallable.elideUrl(original));
}
@Test
public void testElideUrl2() {
String original =
"exception at org.chromium.chrome.browser.crash.LogcatExtractionCallableTest";
assertEquals(original, LogcatExtractionCallable.elideUrl(original));
}
@Test
public void testElideUrl3() {
String original = "file bugs at crbug.com or code.google.com";
String expected = "file bugs at HTTP://WEBADDRESS.ELIDED or HTTP://WEBADDRESS.ELIDED";
assertEquals(expected, LogcatExtractionCallable.elideUrl(original));
}
@Test
public void testElideUrl4() {
String original = "test shorturl.com !!!";
String expected = "test HTTP://WEBADDRESS.ELIDED !!!";
assertEquals(expected, LogcatExtractionCallable.elideUrl(original));
}
@Test
public void testElideUrl5() {
String original = "test just.the.perfect.len.url !!!";
String expected = "test HTTP://WEBADDRESS.ELIDED !!!";
assertEquals(expected, LogcatExtractionCallable.elideUrl(original));
}
@Test
public void testElideUrl6() {
String original = "test a.very.very.very.very.very.long.url !!!";
String expected = "test HTTP://WEBADDRESS.ELIDED !!!";
assertEquals(expected, LogcatExtractionCallable.elideUrl(original));
}
@Test
public void testElideUrl7() {
String original = " at android.content.Intent \n at java.util.ArrayList";
assertEquals(original, LogcatExtractionCallable.elideUrl(original));
}
@Test
public void testElideIp() {
String original = "traceroute 127.0.0.1";
String expected = "traceroute 1.2.3.4";
assertEquals(expected, LogcatExtractionCallable.elideIp(original));
}
@Test
public void testElideMac1() {
String original = "MAC: AB-AB-AB-AB-AB-AB";
String expected = "MAC: 01:23:45:67:89:AB";
assertEquals(expected, LogcatExtractionCallable.elideMac(original));
}
@Test
public void testElideMac2() {
String original = "MAC: AB:AB:AB:AB:AB:AB";
String expected = "MAC: 01:23:45:67:89:AB";
assertEquals(expected, LogcatExtractionCallable.elideMac(original));
}
@Test
public void testElideConsole() {
String original = "I/chromium(123): [INFO:CONSOLE(2)] hello!";
String expected = "I/chromium(123): [ELIDED:CONSOLE(0)] ELIDED CONSOLE MESSAGE";
assertEquals(expected, LogcatExtractionCallable.elideConsole(original));
}
@Test
public void testLogTagNotElided() {
List<String> original = Arrays.asList(new String[] {"I/cr_FooBar(123): Some message"});
assertEquals(original, LogcatExtractionCallable.processLogcat(original));
}
@Test
public void testLogcatEmpty() {
final String original = "";
List<String> expected = new LinkedList<>();
List<String> logcat = null;
try {
logcat = LogcatExtractionCallable.extractLogcatFromReader(
new BufferedReader(new StringReader(original)), MAX_LINES);
} catch (Exception e) {
fail(e.toString());
}
assertArrayEquals(expected.toArray(), logcat.toArray());
}
@Test
public void testLogcatWithoutBeginOrEnd_smallLogcat() {
final List<String> original = Arrays.asList("Line 1", "Line 2", "Line 3", "Line 4",
"Line 5");
assertLogcatLists(original, original);
}
@Test
public void testLogcatWithoutBeginOrEnd_largeLogcat() {
final List<String> original = Arrays.asList("Line 1", "Line 2", "Line 3", "Line 4",
"Line 5", "Redundant Line 1", "Redundant Line 2");
final List<String> expected = Arrays.asList("Line 1", "Line 2", "Line 3", "Line 4",
"Line 5");
assertLogcatLists(expected, original);
}
@Test
public void testLogcatBeginsWithBegin() {
final List<String> original = Arrays.asList(BEGIN_MICRODUMP, "a", "b", "c", "d", "e");
assertLogcatLists(new LinkedList<String>(), original);
}
@Test
public void testLogcatWithBegin() {
final List<String> original = Arrays.asList("Line 1", "Line 2", BEGIN_MICRODUMP, "a",
"b", "c", "d", "e");
final List<String> expected = Arrays.asList("Line 1", "Line 2");
assertLogcatLists(expected, original);
}
@Test
public void testLogcatWithEnd() {
final List<String> original = Arrays.asList("Line 1", "Line 2", END_MICRODUMP);
assertLogcatLists(new LinkedList<String>(), original);
}
@Test
public void testLogcatWithBeginAndEnd_smallLogcat() {
final List<String> original = Arrays.asList("Line 1", "Line 2", BEGIN_MICRODUMP, "a", "b",
"c", "d", "e", END_MICRODUMP);
final List<String> expected = Arrays.asList("Line 1", "Line 2");
assertLogcatLists(expected, original);
}
@Test
public void testLogcatWithBeginAndEnd_largeLogcat() {
final List<String> original = Arrays.asList("Line 1", "Line 2", BEGIN_MICRODUMP, "a", "b",
"c", "d", "e", END_MICRODUMP, "Line 3", "Line 4");
final List<String> expected = Arrays.asList("Line 1", "Line 2", "Line 3", "Line 4");
assertLogcatLists(expected, original);
}
@Test
public void testLogcatWithEndAndBegin_smallLogcat() {
final List<String> original = Arrays.asList(END_MICRODUMP, "Line 1", "Line 2",
BEGIN_MICRODUMP, "a", "b", "c", "d", "e");
final List<String> expected = Arrays.asList("Line 1", "Line 2");
assertLogcatLists(expected, original);
}
@Test
public void testLogcatWithEndAndBegin_largeLogcat() {
final List<String> original = Arrays.asList(END_MICRODUMP, "Line 1", "Line 2",
BEGIN_MICRODUMP, "a", "b", "c", "d", "e", END_MICRODUMP, "Line 3", "Line 4");
final List<String> expected = Arrays.asList("Line 1", "Line 2", "Line 3", "Line 4");
assertLogcatLists(expected, original);
}
private void assertLogcatLists(List<String> expected, List<String> original) {
List<String> actualLogcat = null;
String combinedLogcat = TextUtils.join("\n", original);
try {
//simulate a file reader to test whether the extraction process
//successfully strips microdump from logcat
actualLogcat = LogcatExtractionCallable.extractLogcatFromReader(
new BufferedReader(new StringReader(combinedLogcat)), MAX_LINES);
} catch (Exception e) {
fail(e.toString());
}
assertArrayEquals(expected.toArray(), actualLogcat.toArray());
}
}

@ -15,7 +15,7 @@ make it easy to switch logging on or off for individual groups.
Usage:
```java
private static final String TAG = "cr.YourModuleTag";
private static final String TAG = "YourModuleTag";
...
Log.i(TAG, "Logged INFO message.");
Log.d(TAG, "Some DEBUG info: %s", data);
@ -24,12 +24,13 @@ Log.d(TAG, "Some DEBUG info: %s", data);
Output:
```
I/cr.YourModuleTag: ( 999): Logged INFO message
D/cr.YourModuleTag: ( 999): [MyClass.java:42] Some DEBUG info: data.toString
I/cr_YourModuleTag: ( 999): Logged INFO message
D/cr_YourModuleTag: ( 999): [MyClass.java:42] Some DEBUG info: data.toString
```
Here, **TAG** will be a feature or package name, "MediaRemote" or "NFC" for
example. In most cases, the class name is not needed.
example. In most cases, the class name is not needed. It will be prepended by
the "cr_" prefix to make obvious which logs are coming from Chrome.
### Verbose and Debug logs have special handling ###
@ -50,10 +51,10 @@ Log.i(TAG, "An error happened: %s", e)
```
```
I/cr.YourModuleTag: ( 999): An error happened: This is the exception's message
I/cr.YourModuleTag: ( 999): java.lang.Exception: This is the exception's message
I/cr.YourModuleTag: ( 999): at foo.bar.MyClass.test(MyClass.java:42)
I/cr.YourModuleTag: ( 999): ...
I/cr_YourModuleTag: ( 999): An error happened: This is the exception's message
I/cr_YourModuleTag: ( 999): java.lang.Exception: This is the exception's message
I/cr_YourModuleTag: ( 999): at foo.bar.MyClass.test(MyClass.java:42)
I/cr_YourModuleTag: ( 999): ...
```
Having the exception as last parameter doesn't prevent it from being used for
@ -187,16 +188,16 @@ Logcat allows filtering by specifying tags and the associated level:
```shell
adb logcat [TAG_EXPR:LEVEL]...
adb logcat cr.YourModuleTag:D *:S
adb logcat cr_YourModuleTag:D *:S
```
This shows only logs having a level higher or equal to DEBUG for
`cr.YourModuleTag`, and SILENT (nothing is logged at this level or higher, so it
`cr_YourModuleTag`, and SILENT (nothing is logged at this level or higher, so it
silences the tags) for everything else. You can persist a filter by setting an
environment variable:
```shell
export ANDROID_LOG_TAGS="cr.YourModuleTag:D *:S"
export ANDROID_LOG_TAGS="cr_YourModuleTag:D *:S"
```
For more, see the [related page on developer.android.com]