最近做了个小功能,打算写出来分享一下。文笔不好,标题起得不怎么样,一眼看去可能看不出是要说什么内容,但是又不想起个特别长的标题,就这样吧,随缘
进入正文,最近学习了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打开后就是文章前面截图的效果
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<html>
<head>
<!-- highcharts 需要引用的js库 -->
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
</head>
<style>
body {margin: 0 auto; width:80%; padding: 20px}
</style>
<body>
<div id="level_container" style="width: 100%; height: 300px; margin: 0 auto"></div>
</body>
<script type="text/javascript">
$(document).ready(function() {
var title = { text: 'Battery Level' };
var xAxis = {
// 脚本生成是一行,为了显示清楚手动换行
categories: ['06:15:40.076','06:18:36.180','06:26:30.404','06:33:11.701',
'06:40:53.762','06:46:58.554','06:52:14.718','06:58:37.736',
'07:05:06.852','07:12:36.779','07:20:43.179','07:26:35.815',
'07:32:16.296','07:37:56.775','07:43:37.262','07:49:17.738',
'07:55:22.713','08:00:26.691','08:05:18.531','08:11:56.862',
'08:18:01.665','08:23:50.243','08:25:51.842','08:29:06.399']
};
var yAxis = {title: {text: 'Level'},
plotLines: [{value: 0, width: 1, color: '#808080'}]};
var tooltip = {valueSuffix: ''}
var legend = {layout: 'vertical', align: 'right', verticalAlign: 'middle', borderWidth: 0};
var series = [{
name: 'Level',
data: [91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68]
}];
var json = {};
json.title = title;
json.xAxis = xAxis;
json.yAxis = yAxis;
json.tooltip = tooltip;
json.legend = legend;
json.series = series;
$('#level_container').highcharts(json);
});
</script>
</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("<script type=\"text/javascript\">")
#level
write_report("$(document).ready(function() {")
write_report("var title = { text: 'Battery Level' };")
write_report("var xAxis = {")
timestamps = '['
for i in battery_array:
timestamps = timestamps + "'" + i.timestamp + "',"
timestamps = timestamps[:-1]
timestamps = timestamps + "]"
write_report("categories: " + timestamps)
write_report("};")
write_report("var yAxis = {title: {text: 'Level'},")
write_report("plotLines: [{value: 0, width: 1, color: '#808080'}]};")
write_report("var tooltip = {valueSuffix: ''}")
write_report("var legend = {layout: 'vertical', align: 'right', verticalAlign: 'middle', borderWidth: 0};")
write_report("var series = [{")
write_report("name: 'Level',")
levels = []
for i in battery_array:
levels.append(i.level)
write_report("data: " + str(levels))
write_report("}];")
write_report("var json = {};")
write_report("json.title = title;")
write_report("json.xAxis = xAxis;")
write_report("json.yAxis = yAxis;")
write_report("json.tooltip = tooltip;")
write_report("json.legend = legend;")
write_report("json.series = series;")
write_report("$('#level_container').highcharts(json);")
write_report("});")
# voltages
write_report("$(document).ready(function() {")
write_report("var title = { text: 'Battery Voltage' };")
write_report("var xAxis = {")
timestamps = '['
for i in battery_array:
timestamps = timestamps + "'" + i.timestamp + "',"
timestamps = timestamps[:-1]
timestamps = timestamps + "]"
write_report("categories: " + timestamps)
write_report("};")
write_report("var yAxis = {title: {text: 'Voltage (mV)'},")
write_report("plotLines: [{value: 0, width: 1, color: '#808080'}]};")
write_report("var tooltip = {valueSuffix: 'mV'}")
write_report("var legend = {layout: 'vertical', align: 'right', verticalAlign: 'middle', borderWidth: 0};")
write_report("var series = [{")
write_report("name: 'Voltage',")
voltages = []
for i in battery_array:
voltages.append(i.voltage)
write_report("data: " + str(voltages))
write_report("}];")
write_report("var json = {};")
write_report("json.title = title;")
write_report("json.xAxis = xAxis;")
write_report("json.yAxis = yAxis;")
write_report("json.tooltip = tooltip;")
write_report("json.legend = legend;")
write_report("json.series = series;")
write_report("$('#voltage_container').highcharts(json);")
write_report("});")
# temperature
write_report("$(document).ready(function() {")
write_report("var title = { text: 'Battery Temperature' };")
write_report("var xAxis = {")
timestamps = '['
for i in battery_array:
timestamps = timestamps + "'" + i.timestamp + "',"
timestamps = timestamps[:-1]
timestamps = timestamps + "]"
write_report("categories: " + timestamps)
write_report("};")
write_report("var yAxis = {title: {text: 'Temperature (\\xB0C)'},")
write_report("plotLines: [{value: 0, width: 1, color: '#808080'}]};")
write_report("var tooltip = {valueSuffix: '\\xB0C'}")
write_report("var legend = {layout: 'vertical', align: 'right', verticalAlign: 'middle', borderWidth: 0};")
write_report("var series = [{")
write_report("name: 'Temperature',")
temperatures = []
for i in battery_array:
temperatures.append(i.temperature)
write_report("data: " + str(temperatures))
write_report("}];")
write_report("var json = {};")
write_report("json.title = title;")
write_report("json.xAxis = xAxis;")
write_report("json.yAxis = yAxis;")
write_report("json.tooltip = tooltip;")
write_report("json.legend = legend;")
write_report("json.series = series;")
write_report("$('#temperature_container').highcharts(json);")
write_report("});")
write_report("</script>")
def generate_report(battery_array):
write_report("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\">")
write_report("<html align='left'>")
write_report("<head>")
write_report("<script src=\"http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js\"></script>")
write_report("<script src=\"http://code.highcharts.com/highcharts.js\"></script>")
write_report("</head>")
write_report("<style>")
write_report("body {margin: 0 auto; width:80%; padding: 20px}")
write_report("</style>")
write_report("<body>")
write_report("<div id=\"level_container\" style=\"width: 100%; height: 300px; margin: 0 auto\"></div>")
write_report("<div id=\"voltage_container\" style=\"width: 100%; height: 300px; margin: 0 auto\"></div>")
write_report("<div id=\"temperature_container\" style=\"width: 100%; height: 300px; margin: 0 auto\"></div>")
write_report("</body>")
# 电池电量可视化
battery_report(battery_array)
write_report("</html>")
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("<script type=\"text/javascript\">")
#level
write_report("$(document).ready(function() {")
write_report("var title = { text: 'Battery Level' };")
write_report("var xAxis = {")
timestamps = '['
for i in battery_array:
timestamps = timestamps + "'" + i.timestamp + "',"
timestamps = timestamps[:-1]
timestamps = timestamps + "]"
write_report("categories: " + timestamps)
write_report("};")
write_report("var yAxis = {title: {text: 'Level'},")
write_report("plotLines: [{value: 0, width: 1, color: '#808080'}]};")
write_report("var tooltip = {valueSuffix: ''}")
write_report("var legend = {layout: 'vertical', align: 'right', verticalAlign: 'middle', borderWidth: 0};")
write_report("var series = [{")
write_report("name: 'Level',")
levels = []
for i in battery_array:
levels.append(i.level)
write_report("data: " + str(levels))
write_report("}];")
write_report("var json = {};")
write_report("json.title = title;")
write_report("json.xAxis = xAxis;")
write_report("json.yAxis = yAxis;")
write_report("json.tooltip = tooltip;")
write_report("json.legend = legend;")
write_report("json.series = series;")
write_report("$('#level_container').highcharts(json);")
write_report("});")
# voltages
write_report("$(document).ready(function() {")
write_report("var title = { text: 'Battery Voltage' };")
write_report("var xAxis = {")
timestamps = '['
for i in battery_array:
timestamps = timestamps + "'" + i.timestamp + "',"
timestamps = timestamps[:-1]
timestamps = timestamps + "]"
write_report("categories: " + timestamps)
write_report("};")
write_report("var yAxis = {title: {text: 'Voltage (mV)'},")
write_report("plotLines: [{value: 0, width: 1, color: '#808080'}]};")
write_report("var tooltip = {valueSuffix: 'mV'}")
write_report("var legend = {layout: 'vertical', align: 'right', verticalAlign: 'middle', borderWidth: 0};")
write_report("var series = [{")
write_report("name: 'Voltage',")
voltages = []
for i in battery_array:
voltages.append(i.voltage)
write_report("data: " + str(voltages))
write_report("}];")
write_report("var json = {};")
write_report("json.title = title;")
write_report("json.xAxis = xAxis;")
write_report("json.yAxis = yAxis;")
write_report("json.tooltip = tooltip;")
write_report("json.legend = legend;")
write_report("json.series = series;")
write_report("$('#voltage_container').highcharts(json);")
write_report("});")
# temperature
write_report("$(document).ready(function() {")
write_report("var title = { text: 'Battery Temperature' };")
write_report("var xAxis = {")
timestamps = '['
for i in battery_array:
timestamps = timestamps + "'" + i.timestamp + "',"
timestamps = timestamps[:-1]
timestamps = timestamps + "]"
write_report("categories: " + timestamps)
write_report("};")
write_report("var yAxis = {title: {text: 'Temperature (\\xB0C)'},")
write_report("plotLines: [{value: 0, width: 1, color: '#808080'}]};")
write_report("var tooltip = {valueSuffix: '\\xB0C'}")
write_report("var legend = {layout: 'vertical', align: 'right', verticalAlign: 'middle', borderWidth: 0};")
write_report("var series = [{")
write_report("name: 'Temperature',")
temperatures = []
for i in battery_array:
temperatures.append(i.temperature)
write_report("data: " + str(temperatures))
write_report("}];")
write_report("var json = {};")
write_report("json.title = title;")
write_report("json.xAxis = xAxis;")
write_report("json.yAxis = yAxis;")
write_report("json.tooltip = tooltip;")
write_report("json.legend = legend;")
write_report("json.series = series;")
write_report("$('#temperature_container').highcharts(json);")
write_report("});")
write_report("</script>")
def generate_report(battery_array):
write_report("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\">")
write_report("<html>")
write_report("<head>")
write_report("<script src=\"http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js\"></script>")
write_report("<script src=\"http://code.highcharts.com/highcharts.js\"></script>")
write_report("</head>")
write_report("<style>")
write_report("body {margin: 0 auto; width:80%; padding: 20px}")
write_report("</style>")
write_report("<body>")
write_report("<div id=\"level_container\" style=\"width: 100%; height: 300px; margin: 0 auto\"></div>")
write_report("<div id=\"voltage_container\" style=\"width: 100%; height: 300px; margin: 0 auto\"></div>")
write_report("<div id=\"temperature_container\" style=\"width: 100%; height: 300px; margin: 0 auto\"></div>")
write_report("</body>")
battery_report(battery_array)
write_report("</html>")
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,共勉。