日志,监控、报表数据来源。那么日志的整个生命周期,产生、收集、存储、清洗、查询 是一个重要的问题。
不过开源的Elastic Stack,很不错的一个平台,提供了契合日志所有生命周期的工具,而且通过es本身技术实现,可以快速的针对上亿日志进行分析。
aws cloudwatch logs是熟悉aws平台的另外一个选择。cloudwatch logs结合了aws各种服务,可以实现无缝对接,而且本身一些服务默认日志存储在cloudwatch logs里。所以熟悉cloudwatch logs 是那些依赖于云服务的公司员工的一个重要技能。
关于CloudWatch Logs
- 日志来源和收集:服务器的自建日志(通过cloudwatch logs代理收集),aws服务产生的日志
- 存储: 日志流对应一个来源(比如一个服务器、或服务器上某个服务),日志组整合多个日志流。保留期、访问控制等都是在日志组层。
- 查询: cloudwatch logs insights提供一整套查询语法,方便使用者的分析。
众所周知,aws的基本所有接口会同时提供三种操作手段:控制台、编程方式、aws命令行。同样针对上面三步的操作。
查询CloudWatch Logs
筛选条件和模式语法
可以通过CloudWatch控制台直接在针对日志组、或着某个具体的日志流进行简单查询,如果只是查看某个RequestId所有日志,还是比较方便的。
"c788ad27-3e3b-4560-ac0c-87caea225078"
。将requestid用双引号阔住,输入搜索框中,结果区就会展示该requestid对应的所有日志。
aws logs filter-log-events --log-group-name my-group [--log-stream-names LIST_OF_STREAMS_TO_SEARCH] --filter-pattern "c788ad27-3e3b-4560-ac0c-87caea225078"
CloudWatch Logs Insights
如果分析日志,还是得靠CloudWatch Logs Insights强大的查询来做。
fields @timestamp, @message
| parse @message '* - * [*] "* * *" * * "-" "*"' as host, identity, dateTimeString, httpVerb, url, protocol, status, bytes, useragent
| stats count (*) as all, sum ( status < 299 ) as c_s200, sum ( status > 299 and status < 399 ) as c_s300, sum ( status > 399 and status < 499 ) as c_s400, sum ( status > 499 ) as c_s500 by bin (1m)
查询以管道符分割,支持函数、运算、正则等。
上面的查询分析:
- fields:可以使用支持的函数和运算生成新的临时字段,供后面的查询使用。比如
status == 200 as isSuccess
。功能就像sql里面的as
。示例中列出日志事件中的两个字段,不做变换的情况下可以省略。 - parse:从日志字段中提取新的字段。比如通过正则从@message字段中提取出各部分,生成临时字段或者最终结果展示字段。
- stats by:等同于mysql中的group by,demo中 count、sum为聚合函数,5m代表将数据以五分钟为单位分割为多个桶,分别聚合不同的指标。
另外还有几个关键字比较简单:
- display: 最终结果要展示的字段,类
select
- filter: 筛选指定的条件,简单而又强大。类
where
- limit
翻遍文档,该功能提供的api都是异步的:先提交一个查询,返回一个query_id
; 然后自己轮询
func (c *Clogs) Get(group, filter string, start, end int64) (*cloudwatchlogs.GetQueryResultsOutput, error) {
req, resp := c.c.StartQueryRequest(&cloudwatchlogs.StartQueryInput{
EndTime: aws.Int64(end),
LogGroupName: aws.String(group),
QueryString: aws.String(filter),
StartTime: aws.Int64(start),
})
err := req.Send()
if err != nil {
return nil, err
}
for {
time.Sleep(30 * time.Second)
results, err := c.c.GetQueryResults(&cloudwatchlogs.GetQueryResultsInput{QueryId: resp.QueryId})
if err != nil {
return nil, err
}
if *results.Status != "Scheduled" && *results.Status != "Running" {
if *results.Status != "Complete" {
return nil, errors.New("no complete")
}
return results, nil
}
}
}
注意以下几点:
- 查询超过15分钟,会Timeout,遇到这种情况,分析以下自己的查询语句,适当缩小查询条件
- 查询状态如果 Scheduled | Running,都需要下次重新获取。
总结
依赖于aws云服务的公司,查看日志的需求蛮常见的。CloudWatch Logs Insights方式虽然灵活强大,但是针对简单查看某个Request的相关日志,反而不如直接筛选方便。
引用
https://docs.aws.amazon.com/zh_cn/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html 查询语法 https://docs.aws.amazon.com/zh_cn/AmazonCloudWatchLogs/latest/APIReference/Welcome.html API文档 https://docs.aws.amazon.com/sdk-for-go/api/service/cloudwatchlogs/ golang sdk文档