最近做了个小功能,打算写出来分享一下。文笔不好,标题起得不怎么样,一眼看去可能看不出是要说什么内容,但是又不想起个特别长的标题,就这样吧,随缘
进入正文,最近学习了Python,结合自己当前从事的Android开发的工作,想到了一个小功能,就是通过Python解析android log,提取其中电量的日志进行可视化显示。这是一个很小众的功能,估计基本上不会有人用得上,但是个人感觉是很有趣的一件事。
先上效果图:
文章内容主要是通过以下几个方面描述,尽可能通俗易懂
- 获取日志
- 脚本编写
- 运行结果
1. 获取日志
电池电量信息我们可以从android日志的events log中获取,events log可通过以下命令获取
adb logcat -b events > events.log
其中,电池电量的关键字是battery_level
11-19 06:15:40.076 1502 1538 I battery_level: [91,4164,302]
11-19 06:18:36.180 1502 2042 I battery_level: [90,4224,325]
11-19 06:26:30.404 1502 2042 I battery_level: [89,4203,338]
11-19 06:33:11.701 1502 2042 I battery_level: [88,4179,345]
11-19 06:40:53.762 1502 2042 I battery_level: [87,4184,349]
11-19 06:46:58.554 1502 2042 I battery_level: [86,4160,355]
11-19 06:52:14.718 1502 2042 I battery_level: [85,4150,359]
11-19 06:58:37.736 1502 2042 I battery_level: [84,4143,352]
battery_level
在代码中的描述如下:
battery_level (level|1|6),(voltage|1|1),(temperature|1|1)
- 第一个参数
level
表示当前电池电量 - 第二个参数
voltage
表示当前电池电压 - 第三个参数
temperature
表示当前电池温度
2. 脚本编写
通过battery_level的log格式可以大致得出以下步骤:
- 定义Battery相关类
- 逐行读取events log的日志并提取出
battery_level
行,解析行转换成Battery类 - 通过
highcharts
显示数据
2.1 定义Battery类
class Battery:
# 日期
date = ''
# 时间
timestamp = ''
# 电量
level = 0
# 电压
voltage = 0
# 温度,log中单位需要除以10才是摄氏度的单位,用浮点数表示
temperature = 0.0
2.2 解析日志
# events.log
inputfile = ''
def check_battery():
if os.path.exists(inputfile):
battery_array = []
f = open(inputfile, 'rb')
line = f.readline()
while line:
if "battery_level" in line:
battery = Battery()
temp_line = line.split()
battery.date = temp_line[0]
battery.timestamp = temp_line[1]
# 有些日志可能会有些奇怪的问题,这里加个判断规避异常情况
if len(temp_line) > 6:
# 这里应该是可以用正则表达式进行优化
conf = temp_line[6].replace("[", "").replace("]", "").split(",")
battery.level = int(conf[0])
battery.voltage = int(conf[1])
battery.temperature = int(conf[2]) / 10.0
battery_array.append(battery)
line = f.readline()
f.close()
if len(battery_array) > 0:
# 生成报告,可视化显示,在2.3节中介绍
generate_report(battery_array)
else:
print ("No evnet log file found")
print ("Done")
2.3 可视化显示
结果是通过html显示,用到的是highchart
显示折线图。这里不详细介绍highcharts
的使用,有兴趣的可自行搜索了解。这里简单介绍一下highcharts
的参数
- title: 标题
- xAxis: 横坐标的值和描述
- tooltip: 折线弹出气泡
- legend: 图表样式
- series: 折线数据
先将运行后生成的html简化后内容贴出来会比较容易理解生成报告的脚本,以下内容直接复制到一个文本文件,修改后缀为html打开后就是文章前面截图的效果
脚本没什么特别的地方,就是打开文件写内容:
# report.html
outputfile = ''
def write_report(line):
f = open(outputfile, 'a+')
f.write(line)
f.write('\n')
f.close()
def battery_report(battery_array):
write_report("")
def generate_report(battery_array):
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
# 电池电量可视化
battery_report(battery_array)
write_report("")
3. 运行结果
附上所有代码,加上命令行传参功能:
import getopt
import os
import sys
inputfile = ''
outputfile = 'report.html'
class Battery:
date = ''
timestamp = ''
level = 0
voltage = 0
temperature = 0.0
def write_report(line):
f = open(outputfile, 'a+')
f.write(line)
f.write('\n')
f.close()
def battery_report(battery_array):
write_report("")
def generate_report(battery_array):
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
write_report("")
battery_report(battery_array)
write_report("")
def check_battery():
if os.path.exists(inputfile):
battery_array = []
f = open(inputfile, 'rb')
line = f.readline()
while line:
if "battery_level" in line:
battery = Battery()
temp_line = line.split()
battery.date = temp_line[0]
battery.timestamp = temp_line[1]
if len(temp_line) > 6:
conf = temp_line[6].replace("[", "").replace("]", "").split(",")
battery.level = int(conf[0])
battery.voltage = int(conf[1])
battery.temperature = int(conf[2]) / 10.0
battery_array.append(battery)
line = f.readline()
f.close()
if len(battery_array) > 0:
generate_report(battery_array)
else:
print ("No evnet log file found")
print ("Done")
def remove_report():
if os.path.exists(outputfile):
os.remove(outputfile)
def help():
print ("python check_battery.py -i event.log -o report.html")
def main(argv):
if len(argv) < 1:
print ("args must more than one. please use -h to see more")
sys.exit()
try:
opts, args = getopt.getopt(argv, "hi:o:",["inputfile=", "outputfile="])
except getopt.GetoptError:
sys.exit(2)
for opt, arg in opts:
if opt == "-h":
help()
sys.exit()
elif opt in ("-i", "--inputfile"):
global inputfile
inputfile = arg
elif opt in ("-o", "--outputfile"):
if not arg.endswith(".html"):
arg = arg + ".html"
global outputfile
outputfile = arg
remove_report()
check_battery()
if __name__ == "__main__":
main(sys.argv[1:])
运行:
$ python check_battery.py -i event.log
输出结果:report.html
总结
python确实是个特别好的工具,工作中有很大的帮助。工作中我不止写了解析电池的脚本,还写了解析属性文件、应用信息、系统设置的脚本,后续还会考虑使用脚本解析anr、watchdog等trace log。当然,这个解析工作有些复杂,特别是watchdog类型的trace要考虑的情况比较多,先立个flag,共勉。