/*
* Tencent is pleased to support the open source community by making
* Tencent GT (Version 2.4 and subsequent versions) available.
*
* Notwithstanding anything to the contrary herein, any previous version
* of Tencent GT shall not be subject to the license hereunder.
* All right, title, and interest, including all intellectual property rights,
* in and to the previous version of Tencent GT (including any and all copies thereof)
* shall be owned and retained by Tencent and subject to the license under the
* Tencent GT End User License Agreement (http://gt.qq.com/wp-content/EULA_EN.html).
*
* Copyright (C) 2015 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* 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.tencent.wstt.gt.log;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.text.TextUtils;
import com.tencent.wstt.gt.dao.GTPref;
import com.tencent.wstt.gt.ui.model.LogEntry;
import com.tencent.wstt.gt.ui.model.MatchedEntry;
import com.tencent.wstt.gt.utils.GTUtils;
public class GTLogInternal {
/*
* 注意在array.xml中有对应,需要同时改;客户端中AbsConnState类里也要对应
*/
public static final int LOG_VERBOSE = 0; // 全部
public static final int LOG_DEBUG = 1; // 调试
public static final int LOG_INFO = 2; // 信息
public static final int LOG_WARNING = 3; // 警告
public static final int LOG_ERROR = 4; // 错误
public static int Log_Level = LOG_VERBOSE; // 显示的log级别,起到开关的作用
// 因为Activity的生命周期不太靠谱,所以在这里保存上次的文件名
private static String lastSaveLog = "GTLog";
// 日志的日期部分长度是19
private static final int TIMESTAMP_LENGTH = 19;
// 去掉日期,logcat的匹配模式
private static Pattern logPattern = Pattern.compile(
// level
"(\\w)" +
"/" +
// tag
"([^(]+)" +
"\\(\\s*" +
// pid
"(\\d+)" +
// optional weird number that only occurs on ZTE blade
"(?:\\*\\s*\\d+)?" +
"\\): ");
// 常规日志的控制
private static LogController logController = new LogController();
private static LogTaskConsumer logTaskConsumer;
private static TempLogConsumer tempLogConsumer = new TempLogConsumer(logController);
private static NormalLogAdapter curLogAdapter;
static {
tempLogConsumer.start();
}
// 日志搜索控制
private static LogSearchController logSearchController = new LogSearchController();
private static boolean log_enable_flag =
GTPref.getGTPref().getBoolean(GTPref.LOG_MASTER_SWITCH, true);
public static void setCurLogAdapter(NormalLogAdapter curLogAdapter)
{
GTLogInternal.curLogAdapter = curLogAdapter;
}
public NormalLogAdapter getCurLogAdapter()
{
return curLogAdapter;
}
public static List<LogEntry> getNormalLogList()
{
return logController.getShowLogList();
}
public static LogEntry[] getCurNormalLogs()
{
LogEntry[] result = {};
GTLogInternal.getLogListReadLock().lock();
List<LogEntry> list = logController.getShowLogList();
result = list.toArray(result);
GTLogInternal.getLogListReadLock().unlock();
return result;
}
public static LogEntry[] getCurFilteredLogs()
{
LogEntry[] result = {};
GTLogInternal.getLogListReadLock().lock();
List<LogEntry> list = logController.getFilterdLogList();
result = list.toArray(result);
GTLogInternal.getLogListReadLock().unlock();
return result;
}
public static void setFilterdLogList(List<LogEntry> list)
{
logController.setFilterdLogList(list);
}
public static int getNormalLogLastFilterEndLocation()
{
return logController.getLastFilterEndLocation();
}
public static void resetNormalLogLastFilterEndLocation()
{
logController.resetLastFilterEndLocation();
}
public static List<String> getTags()
{
return logController.getShowTags();
}
/*
* 将ShowLogList的读锁返回,交给调用端维护
*/
public static Lock getLogListReadLock()
{
return logController.lock.readLock();
}
// 日志过滤下拉菜单相关接口
public static int getCurFilterLevel() {
return logController.getCurSelectedLevel();
}
public static void setCurFilterLevel(int curSelectedLevel) {
logController.setCurSelectedLevel(curSelectedLevel);
}
public static String getCurFilterTag() {
return logController.getsCurSelectedTag();
}
public static void setCurFilterTag(String sCurSelectedTag) {
logController.setsCurSelectedTag(sCurSelectedTag);
}
public static String getCurFilterMsg() {
return logController.getsCurSelectedMsg();
}
public static void setCurFilterMsg(String sCurSelectedMsg) {
logController.setsCurSelectedMsg(sCurSelectedMsg);
}
public static LinkedList<String> getCurFilterMsgHistory() {
return logController.getMsgHistory();
}
public static LinkedList<String> getCurFilterShowDownMsgList() {
return logController.getCurShowDownMsgList();
}
/*
* 搜索相关接口
*/
public static String getLastSearchMsg() {
return logSearchController.getLastSearchMsg();
}
public static void setLastSearchMsg(String lastSearchMsg) {
logSearchController.setLastSearchMsg(lastSearchMsg);
}
public static LogEntry[] getLastSearchDataSet() {
return logSearchController.getLastEntrys();
}
public static void setLastSearchDataSet(LogEntry[] lastEntrys) {
logSearchController.setLastEntrys(lastEntrys);
}
public static List<MatchedEntry> getLastMatchedEntryList() {
return logSearchController.getLastMatchedEntryList();
}
public static void clearLastSearchMarks()
{
logSearchController.clear();
}
public static int getLastMatchedSeq()
{
return logSearchController.getLastMatchedSeq();
}
public static void setLastMatchedSeq(int lastMatchedSeq)
{
logSearchController.setLastMatchedSeq(lastMatchedSeq);
}
// 搜索下拉菜单相关接口
public static LinkedList<String> getCurSearchMsgHistory() {
return logSearchController.getMsgHistory();
}
public static LinkedList<String> getCurShowDownMsgList() {
return logSearchController.getCurShowDownMsgList();
}
public static String getCurSearchMsg() {
return logSearchController.getsCurSelectedMsg();
}
public static void setCurSearchMsg(String sCurSelectedMsg) {
logSearchController.setsCurSelectedMsg(sCurSelectedMsg);
}
// 从界面上设置,传进来用户定义的显示级别
public static void setLogLevel(int level) {
Log_Level = level;
}
public static void logCat(String originalLine)
{
// 先解析日志
String sTime = null;
long pid = -1;
char level = 'I';
String tag = null;
String msg = null;
int startIdx = 0;
if (!TextUtils.isEmpty(originalLine)
&& Character.isDigit(originalLine.charAt(0))
&& originalLine.length() >= TIMESTAMP_LENGTH) {
String timestamp = originalLine.substring(0, TIMESTAMP_LENGTH - 1);
sTime = timestamp;
startIdx = TIMESTAMP_LENGTH; // cut off timestamp
}
Matcher matcher = logPattern.matcher(originalLine);
if (matcher.find(startIdx)) {
level = matcher.group(1).charAt(0);
int gtLevel = LOG_VERBOSE;
switch (level)
{
case 'V':
gtLevel = LOG_VERBOSE;
break;
case 'D':
gtLevel = LOG_DEBUG;
break;
case 'I':
gtLevel = LOG_INFO;
break;
case 'W':
gtLevel = LOG_WARNING;
break;
case 'E':
gtLevel = LOG_ERROR;
break;
}
tag = matcher.group(2);
pid = Integer.parseInt(matcher.group(3));
msg = originalLine.substring(matcher.end());
log(pid, gtLevel, tag, msg, sTime);
}
}
public static void log(long pid, int level, String tag, String msg, String sTime) {
if (level < Log_Level) {
return;
}
if (! log_enable_flag) {
return;
}
if (level > LOG_ERROR || null == tag || null == msg)
{
return;
}
// 第一次打日志,初始化日志消费者对象。TODO 按道理说应该加锁。
if (null == logTaskConsumer)
{
logTaskConsumer = new LogTaskConsumer(logController);
logTaskConsumer.setAllowAdd2Visable(log_enable_flag);
logTaskConsumer.start();
}
char sLevel = 'V';
switch (level) {
case LOG_VERBOSE:
sLevel = 'V';
break;
case LOG_DEBUG:
sLevel = 'D';
break;
case LOG_INFO:
sLevel = 'I';
break;
case LOG_WARNING:
sLevel = 'W';
break;
case LOG_ERROR:
sLevel = 'E';
break;
}
String time = sTime;
if (sTime == null)
{
time = GTUtils.getSystemDateTime();
}
LogEntry entry = new LogEntry();
entry.tid = pid;
entry.tag = tag;
entry.level = level;
if (isSaveDefaultSeg())
{
StringBuffer sb = new StringBuffer();
sb.append(time);
sb.append(": ");
sb.append(sLevel);
sb.append("/"); // sb.append(" | ");
sb.append(tag);
sb.append("("); // sb.append(" | ");
sb.append(pid);
sb.append("): "); // sb.append(" : ");
sb.append(msg);
// sb.append("\r\n"); // 因为UI与自动保存分开了,所以不能统一加换行了
entry.msg = sb.toString();
}
else
{
entry.msg = msg;
}
entry.sTime = time;
logTaskConsumer.putLog(entry);
tempLogConsumer.putLog(entry.msg);
}
public static void enable()
{
log_enable_flag = true;
GTPref.getGTPref().edit().putBoolean(GTPref.LOG_MASTER_SWITCH, true).commit();
if (null != logTaskConsumer)
{
logTaskConsumer.setAllowAdd2Visable(true);
}
}
public static void disable()
{
log_enable_flag = false;
GTPref.getGTPref().edit().putBoolean(GTPref.LOG_MASTER_SWITCH, false).commit();
if (null != logTaskConsumer)
{
logTaskConsumer.setAllowAdd2Visable(false);
}
}
public static boolean isEnable()
{
return log_enable_flag;
}
public static void setSaveDefaultSeg(boolean flag)
{
if (null != logController)
{
logController.setSaveDefaultSeg(flag);
}
}
public static boolean isSaveDefaultSeg()
{
if (null != logController)
{
return logController.getSaveDefaultSeg();
}
return false;
}
public static void setAutoSave(boolean flag)
{
if (null != logController)
{
logController.setAutoSave(flag);
}
}
public static boolean isAutoSave()
{
if (null != logController)
{
return logController.getAutoSave();
}
return false;
}
public static boolean hasLogNeedIO()
{
if (null != logController)
{
// return logController.hasTempLog(); //TODO 自动写日志合入前用这个
return logController.getAutoSave() || logController.hasTempLog();
}
return false;
}
public static void saveLog(String logFileName)
{
setLastSaveLog(logFileName);
logController.saveCache(logFileName);
}
public static String getLastSaveLog() {
return lastSaveLog;
}
public static void setLastSaveLog(String lastSaveLogName) {
GTLogInternal.lastSaveLog = lastSaveLogName;
}
/**
* 开始记录临时日志,文件名要合法,默认保存在mnt/sdcard/GT/Log/目录下
* @param logFileName 合法的文件名,不需要加后缀
* @throws IOException 如文件名不合法或没有创建文件的权限,会抛出该异常
*/
public static void startLog(String logFileName) throws IOException {
tempLogConsumer.startALog(logFileName);
}
public static void endLog(String logFileName) {
tempLogConsumer.endALog(logFileName);
}
public static void endAllLog() {
logController.endAllLog();
}
public static void cleanLog(String logFileName) {
tempLogConsumer.cleanALog(logFileName);
}
/**
* 清除屏幕上的日志
*/
public static void clearLog()
{
logController.clearCache();
}
/*
* 被测App变化,也有改变保存日志的根目录
* TODO 适配到支持多应用后,该方法暂无使用了
*/
public static void changeCurAppName(String name)
{
logController.changeCurrentLogFolder(name);
}
public static void addLogListener(LogListener listener)
{
logController.addListener(listener);
}
public static void removeLogListener(LogListener listener)
{
logController.removeListener(listener);
}
}