Java tutorial
/* * Copyright (C) 2010 The SendMeLogs for Android project * * 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. */ package com.triarc.sync; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; import org.apache.http.protocol.HTTP; import org.json.JSONObject; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.net.Uri; import android.os.Build; import android.os.Handler; import android.util.Log; /** * A portion of this class is based on android-log-collector * (http://code.google.com/p/android-log-collector/) * * @author lintonye * */ public class LogCollector { public final static String LINE_SEPARATOR = System.getProperty("line.separator");//$NON-NLS-1$ private static final String LOG_TAG = LogCollector.class.getSimpleName(); private Context mContext; private String mPackageName; private Pattern mPattern; private SharedPreferences mPrefs; private ArrayList<String> mLastLogs; public LogCollector(Context context) { mContext = context; mPackageName = context.getPackageName(); String pattern = String.format("(.*)E\\/AndroidRuntime\\(\\s*\\d+\\)\\:\\s*at\\s%s.*", mPackageName.replace(".", "\\.")); mPattern = Pattern.compile(pattern); mPrefs = mContext.getSharedPreferences("LogCollector", Context.MODE_PRIVATE); mLastLogs = new ArrayList<String>(); } @SuppressWarnings("unchecked") private void collectLog(List<String> outLines, String format, String buffer, String[] filterSpecs) { /*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) -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"*/ outLines.clear(); ArrayList<String> params = new ArrayList<String>(); if (format == null) { format = "time"; } params.add("-v"); params.add(format); if (buffer != null) { params.add("-b"); params.add(buffer); } if (filterSpecs != null) { for (String filterSpec : filterSpecs) { params.add(filterSpec); } } final StringBuilder log = new StringBuilder(); try { ArrayList<String> commandLine = new ArrayList<String>(); commandLine.add("logcat");//$NON-NLS-1$ commandLine.add("-d");//$NON-NLS-1$ commandLine.addAll(params); Process process = Runtime.getRuntime().exec(commandLine.toArray(new String[0])); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = bufferedReader.readLine()) != null) { outLines.add(line); } } catch (IOException e) { Log.e(LOG_TAG, String.format("collectAndSendLog failed - format:%s, buffer:%s, filterSpecs:%s", format, buffer, filterSpecs), e); } } public boolean hasForceCloseHappened() { String[] filterSpecs = { "*:E" }; //{"AndroidRuntime:E"}; // for some reason, AndroidRuntime:E lists all logs ArrayList<String> lines = new ArrayList<String>(); collectLog(lines, "time", null, filterSpecs); if (lines.size() > 0) { boolean forceClosedSinceLastCheck = false; for (String line : lines) { final Matcher matcher = mPattern.matcher(line); boolean isMyStackTrace = matcher.matches(); SharedPreferences prefs = mPrefs; if (isMyStackTrace) { String timestamp = matcher.group(1); boolean appeared = prefs.getBoolean(timestamp, false); // Log.d(LOG_TAG, lineKey); if (!appeared) { // Log.d(LOG_TAG, "!appeared"); forceClosedSinceLastCheck = true; prefs.edit().putBoolean(timestamp, true).commit(); } } } return forceClosedSinceLastCheck; } else return false; } private String collectPhoneInfo() { return String.format("Carrier:%s\nModel:%s\nFirmware:%s\n", Build.BRAND, // Build.DEVICE, // Build.BOARD, // Build.DISPLAY, Build.MODEL, // Build.PRODUCT, Build.VERSION.RELEASE); } public boolean collect() { ArrayList<String> lines = mLastLogs; collectLog(lines, null, null, null); return lines.size() > 0; } public void sendLog(String url) { ArrayList<String> lines = mLastLogs; if (lines.size() > 0) { StringBuilder sb = new StringBuilder(); String phoneInfo = collectPhoneInfo(); sb.append(LINE_SEPARATOR).append(phoneInfo); for (String line : lines) sb.append(LINE_SEPARATOR).append(line); String content = sb.toString(); sendLog(url, content); } } private void sendLog(final String url, final String content) { HttpPost httppost = new HttpPost(url + "/ClientLogger/LogMobile"); try { this.mLastLogs.clear(); httppost.setEntity(new StringEntity(content, HTTP.UTF_8)); DefaultHttpClient httpclient = new DefaultHttpClient(new BasicHttpParams()); HttpResponse response = httpclient.execute(httppost); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); Handler handler = new Handler(); handler.postDelayed(new Runnable() { public void run() { LogCollector.this.sendLog(url, content); } }, 5000); } catch (Exception e) { e.printStackTrace(); } } }