日志的可视化---基本实现以及扩展

现状:原先公司服务器的日志是用来事后调试。日志是根据时间按照键值对存储的本地文件。业务繁忙或日子一长,便会产生大量无效的文件。除此之外,别无他用。

目标:从日志中提取有用的信息。从软件上可以获取一定时间内的IO性能;客户端请求的统计。从业务上则可以获取更多。

这是大致的工作流程。

image

技能预备:

python 3.4文本分析和数据处理快速开发,快速实现业务
mongodb键值对的存储数据由于业务不同,相关的键值对也不一致,所以采用nosql
mysql最终记录的管理具体业务的最终结果是相对固定的,同时也为了后续客户端的快速访问
workbench数据库table的维护数据库维护工具
c# && wcf服务端,给浏览器提供数据支持构建一个简单的服务端,支持浏览器的post方式获取数据
Javascript && HTML客户端界面和操作html,javascript分离界面和业务,手工绑定数据
Fiddler测试wcf请求测试客户端的请求和返回值,调试封装后的API

如何安装这些软件,就不在这里详述了。

测试环境:

windows 2008 r2c#,workbench
ubuntu14.04mongodb,mysql

实现过程:

1. 原始日志文件的输入

日志基本说明:

文件按照目录存放,日志内容是有时序。

每条日志占用一行。

它的格式如下:2015-11-09 07:37:09 Request sn=0 topic=\RealTime\SEHKFeed\6881 fields=<F>P1<D>6881<F>P2<D>CGS<F>P3<D>中國銀河<F>P4<D>中国银河<F>P6<D>7.730<F>P15<D>500

时间2015-11-09 07:37:09
关键字\RealTime\SEHKFeed\6881
数据<F>P1<D>6881<F>P2<D>CGS<F>P3<D>中國銀河<F>P4<D>中国银河<F>P6<D>7.730<F>P15<D>500

实现文件列表:

pyCollectMore.py启动脚本,设置参数,捕获错误
pyScanner.py枚举目录的文件,并发pyResolve(由于开发时间有限,暂时做成单线程的方法调用了)
pyStoreDefine.py常量定义
mongoAccesslib.pymongodb api封装
pyResolve.py利用正则表达式分析日志行,写入mongo数据库

开发细节:

1. 由于日志之间有时间顺序,所以同一个目录的文件需要依次遍历,但不同目录可以并行执行。

2. 主要是日志topic对象的信息分解。

原始数据如下:

2015-11-09 07:37:09 Request sn=0 topic=\RealTime\SEHKFeed\6881 fields=<F>P1<D>6881<F>P2<D>CGS<F>P3<D>中國銀河<F>P4<D>中国银河<F>P6<D>7.730<F>P15<D>500

分解1:获取时间,topic名称,原始键值对。

正则表达式:(\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d)\s(?:Request|Update)\ssn=0\stopic=\\([\S]+)\\([\S]+)\sfields=(.+)

分解2:键值对。

正则表达式:<F>([^<]+)<D>([^<]*)

整理和合并日志记录:

对于一个topic而言,包含2部分:命名空间和topic对象名称。

在之前的示例中“\RealTime\SEHKFeed\6881”---命名空间:“\RealTime\SEHKFeed”;对象是:“6881”。

所以处理完成全部的日志行后,需要合并相同命名空间下的对象名称。

2. 中间结果的存储

在之前任务中,我们可以获取2部分的信息:topic的明细以及topic的清单。

这时候需要在mongodb中创建2个表。

tb_topic_list记录已收集的topic对象名称
tb_命名空间根据日志收集后的命名空间,创建对应的表,存放每个topic的全部明细

这时候使用nosql的好处了,事先不用定义表以及相关字段。

tb_topic_list字段定义:

_id记录id
tps新建表名称,后续调度程序使用
tpn对象名称
tpu是否已经处理过

tb_命名空间(根据上下文应该是tb_RealTime_SEHKFeed)字段定义:

_id记录id
nss记录序列号(python维护)
nstptopic名称
nsd时间
nsn命名空间
业务的字段P1,P2..

 

3. 任务调度和数据分析

实现文件列表:

pyTaskMng.py启动脚本,定时查询待处理的topic,并发执行pyReduce(topic数量很多,所以这里是并发进程)
pyReduce.py从mongodb获取已经分类的topic,根据时间顺序,计算总数,最大值,最小值以及记录明细
pyStoreDefine.py常量定义
mongoAccesslib.pymongodb api封装
mysql.connectormysql官方引用,在reduce之后写入计算的结果

开发细节:

1. pyTaskMng运行在不同的机器上,定时检查tb_topic_list。

如果有记录上, 并发交给进程池,由pyReduce负责获取topic对应的全部记录,数量大的时候,批量获取。

2. pyReduce分批获取topic的明细。

根据业务规则:

P1code
P2名称
P3big5名称
P4gb名称
P5价格
P6数量

由于这个项目属于demo,所以我们假定以下的规则:

开盘价每个股票第一笔价格
收盘价每个股票最后一笔价格
最高价 初值等于开盘价,比较当前价后判断是否更改
最低价初值等于开盘价,比较当前价后判断是否更改
变化次数累计记录数
成交量每个记录报价数

pyReduce并发执行,执行完成后更新tb_topic_list。

计算的结果存入mysql表。

4. 最终结果的存储

鉴于nosql在统计查询上有些限制,所以使用mysql作为统计信息的存储设备。

secDaily表记录统计信息

字段类型说明
tIDint主键
codevarchar(45)股票code
secNamevarchar(32)股票名称
nsvarchar(64)命名空间
secTimedatetime日期
dayNumint逻辑天
openPrice double开盘价
closePricedouble收盘价
highPricedouble最高价
lowPricedouble最低价
changeTotalint变化次数
exQtydouble成交量

secDetail表记录时间戳

字段类型说明
sdIDint主键
secDailyIDint主表id
seqint序列号
detailTimedatetime时间戳
pricedouble价格
qtydouble数量

5. 提供数据的服务端

为了快速显示,这次使用wcf作为服务端。

提供5个接口:

获取指定sec列表总数 
 select count(tID) from secDaily where secCode like '%{0}%' or secName like '%{0}%';
 http://localhost:8000/DEMOService/secSum
 

R:  {"filter" :"1"}   
S: {"cookie":0,"total":279}

获取批量sec列表 
 

select secCode,secName,ns,DATE_FORMAT(secTime,'%Y-%m-%%d %H:%i:%S'),openPrice,closePrice

,highPrice,lowPrice,changeTotal,exQty 

from secDaily

where secCode like '%{0}%' or secName like '%{0}%' 

order by  secCode limit {1},{2};

 http://localhost:8000/DEMOService/secbatch
 

R: {"filter" :"1", "offset": 0,"count":10}                  
S:{"cookie": 0,
         "items": [
             {
                 "changeTotal": 21728,
                 "closePrice": 104.1,
                 "exQty": 10864000,
                 "highPrice": 104.1,
                 "lowPrice": 104.1,
                 "ns": "RealTime-SEHKFeed",
                 "openPrice": 104.1,
                 "secCode": "1",
                 "secName": "CKH HOLDINGS",
                 "secTime": "2015-11-09 09:51:11"
             }
         ]
     }

获取指定sec明细总数 
 

select count(sdID) from secDetail 

inner join secDaily on secDetail.secDailyID = secDaily.tID

where secDaily.secCode = '{0}';

 http://localhost:8000/DEMOService/detailSum
 

R:{"code" :"1"}
S:{"total":21728}

获取指定sec批量列表(关键是item的时间)    
 select seq,DATE_FORMAT(detailTime,'%Y-%m-%%d %H:%i:%S')
from secDetail 
inner join secDaily on secDetail.secDailyID = secDaily.tID
where secDaily.secCode = '{0}'  order by seq  limit {1},{2};  
 获取指定sec批量列表
 

R:  {"code" :"1", "offset": 0,"count":2}
S:{ "cookie": 0,
        "items": [
            {
                "detailTime": "2015-11-09 09:51:11",
                "seq": 45
            },
            {
                "detailTime": "2015-11-09 09:51:11",
                "seq": 46
            }
        ]
    }

获取指定时间内统计 
 create procedure getRange(codeRange varchar(45), beginTime varchar(20), endTime varchar(20),rangval int)
需要构建临时表,填充空记录
 http://localhost:8000/DEMOService/rangeTotal

客户端通过浏览器使用POSt方式查询数据.所以服务器请求需要特别处理。

[ServiceContract(Name = "RESTDemoServices")]
public interface IRESTDemoServices
{
    [OperationContract]
    [WebInvoke(UriTemplate = "secSum", Method = "*", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
     SecSumResponse GetSecSum(SecSumRequest req);
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single, IncludeExceptionDetailInFaults = true)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[JavascriptCallbackBehavior(UrlParameterName = "callback")]
public class RestDemoServices : BaseEntry.IRESTDemoServices
{
    public SecSumResponse GetSecSum(SecSumRequest req)
    {
           
            if (WebOperationContext.Current.IncomingRequest.Method == "OPTIONS")
            {
                WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
                WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST");
                WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept");

                return null;
            }
            WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
            SecSumResponse resp = new SecSumResponse();
    }
}

6. 客户端实现 Javascript, chart.JS

实现文件列表:

main.htm界面布局
bigDataStyle.csscss
jquery-1.11.2.jsjquery
mainImpl.js界面实现脚本
SecDailyApi.jsapi封装脚本
table.js表格脚本
Chart.JSChart.JS引用

效果图

image

测试文件:ch1.fxl

7. 接下来可以做的任务

这个项目属于demo性质。下一步预备使用java改写python的实现,scan和reduce部分的存储可能考虑hadoop实现存储和分发。

源代码:https://github.com/febwave/pybig

转载于:https://www.cnblogs.com/febwave/p/5036664.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值