SPL

2019-11-20-SPL

堆 栈 队列

参考

  • 参考1

  • 参考2

  • 参考3

  • 堆:

    • 堆是在程序运行时,而不是在程序编译时,申请某个大小的内存空间。即动态分配内存,对其访问和对一般内存的访问没有区别。
    • 堆是应用程序在运行的时候请求操作系统分配给自己内存,一般是申请/给予的过程。
    • 堆是指程序运行时申请的动态内存,而栈只是指一种使用堆的方法(即先进后出)。
  • 堆区:由程序员分配释放,若程序员不释放,程序结束时可能有OS回收(引用类型值)。

  • 栈:

    • 一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。
    • 栈就是一个桶,后放进去的先拿出来,它下面本来有的东西要等它出来之后才能出来(先进后出)。
    • 栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域。
  • 栈区:由编辑器自动分配释放,存放函数的参数值,局部变量的值等(基本类型值)。

  • 队列:

    • 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行删除操作的端称为队头,进行插入操作的端称为队尾。
    • 队列中没有元素时,称为空队列。
    • 建立顺序队列结构必须为其静态分配或动态申请一片连续的存储空间,并设置两个指针进行管理。一个是队头指针front,它指向队头元素;另一个是队尾指针rear,它指向下一个入队元素的存储位置。
    • 队列采用的FIFO(first in first out),新元素(等待进入队列的元素)总是被插入到链表的尾部,而读取的时候总是从链表的头部开始读取。每次读取一个元素,释放一个元素。所谓的动态创建,动态释放。因而也不存在溢出等问题。由于链表由结构体间接而成,遍历也方便。(先进先出)
  • 堆栈的特性:

    • 堆本身就是栈,最后一个放入堆栈中的物体总是被最先拿出来, 这个特性通常称为后进先出(LIFO)队列。
    • 堆栈中定义了一些操作,两个最重要的是PUSH和POP。 PUSH操作在堆栈的顶部加入一 个元素。POP操作相反,在堆栈顶部移去一个元素,并将堆栈的大小减一。

链表

  • 链表中每一个元素都是一个对象,每个对象称为一个节点,包含有数据域key和指向下一个节点的指针next。通过各个节点之间的相互连接,最终串联成一个链表。

关于SPL

SPL:Search Process Language(搜索处理语言)

1
2
3
4
5
6
AND OR () NOT 
通配符:'* ? []'
field:[x TO y]

cat /var/log/messages |grep Error |awk '{print substr($3,1,5)}' |sort |uniq -c |sort -nr |head 10
source:"/var/log/messages" Error |bucket timestamp sapn=1m as ts |stats count() by ts |sort by 'count()' |limit 10

常用命令

stats

提供统计信息,可以选择按照字段分组(单值统计)
* count() – 返回字段出现次数,统计事件数

1
2
3
# 统计ip和stats的组合的事件数量
logtype:apache
|stats count() by apache.clientip,apache.status

  • avg() – 返回字段平均值

    1
    2
    3
    4
    # 统计平均值
    logtype:apache
    |stats avg(apache.resp_len) as avg_resp_len by apache.request_path
    |rename avg_resp_len as "平均响应长度"

  • sum()

    1
    2
    3
    # 统计日志量
    * |stats sum(raw_message_length) as byte
    |eval Mb=byte/1024/1024

  • max()

  • min()

  • dc() – 返回字段唯一个数,去重,dedup field

bucket

将字段连续的值放到离散的数据桶中,可用于后续的stats等命令分组字段中

1
2
3
4
5
6
7
8
9
10
/*每1小时跨度内每个hostname的apache.resp_len平均值*/
logtype:apache
|bucket timestamp span=1h as ts
|stats avg(apache.resp_len) by hostname,ts
|eval ts_human=foramtdate(ts)
/******/
/*返回apache.status为100-200,200-400,400以上的apache.status事件数*/
logtype:apache
|bucket apache.status ranges=((100,200),(200,400),(400,)) as rs
|stats count(apache.status) by rs

rename

重命名指定字段,支持对多字段同时进行重命名用,分开,支持通配符

1
2
logtype:apache 
|rename apache.clientip as "ip地址"

eval

计算表达式并将生成值放到新的字段中,存在将覆盖
常用函数:todouble()、formatdate(timestamp,“HH:mm”)
* 根据响应时间获取short,middle,long三个分类值

1
2
3
4
5
6
7
8
9
10
11
logtype:apache 
|eval length=case(apache.resp_len<1500,"short",apache.resp_len>2000,"long",default,"middle")
|stats count(desc) by desc
/********************************/

logtype:apache
|eval desc=if(apache.status==20,"OK","Error")
|stats count(desc) by desc
/********************************/
logtype apache
|eval int status=tolong(apache.status)

fileds

保留搜索结果中的字段,支持通配

1
2
3
logtype:apache 
|stats count() by appname,hostname
|fields appname,hostname

table

将查询结果以表格形式展示,并对字段进行筛选,若不包含空行显示,支持通配符

1
2
3
4
5
* |table apache.status,apache.method
/*****/
appname:nginx AND nginx.request_time:*
|eval new_reuqest_time=todouble(nginx.request_time)
|table nginx.client_ip.geo.ip,nginx.client_ip.geo.isp,nginx.client_ip.gep.province

makeresults

构造指定的结果
* 产生一条结果并生成新的app字段,用于后续map命令

1
2
3
* | makeresults count=1 
|eval app="zookeeper"
|map "* appname:$app$"

where

使用表达式对结果进行过滤

1
2
3
logtype:apache AND apache.geo.city:"深圳市" 
|stats dc(apache.clientip) as dc_count by apache.request_path
|where dc_count>40 && dc_count<100

top

获取字段出现次数前N的值集合

1
* |top 5 nginx.client_ip.geo.province

limit

返回前n个结果

1
2
3
4
5
logtype:apache |limit 2
/*******/
logtype:apache
|stats count() by apache.clientip
|limit 5

sort

按照指定字段对搜索结果排序,+升序,-降序

1
2
3
4
5
logtype:apache |sort by +timestamp
/********/
logtype:apache
|stats count(apache.clientip) as ip_count by appname
|sort by -ip_count

join

对父管道结果和子管道结果进行类似SQL的join,关联分析
type=left/inner (取左/取并)
* 统计昨天每个小时每个IP的事件数占当前这个小时总数的百分比

1
2
3
4
5
6
7
8
9
logtype:apache 
|bucket timestamp span=1h as ts
|stats count() as ip_count by apache.clientip,ts
|join type=left ts [[
logtype:apache
|bucket timestamp span=1h as ts
|stats count() as hour_count by ts
]]
|eval ippercent=100*ip_count/hour_count

  • 按照运营商ISP统计总数,status:400-499数量及占比,status:500-599数量及占比,请求长度大于1000数量及占比,形成一张统计表
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    logtype:apache 
    |stats count(logtype) as count_all by apache.geo.isp
    |sort by count_all
    |limit 5
    /**************/
    logtype:apache AND apache.status:[400 TO 499]
    |stats count(logtype) as count_400 by apache.geo.isp
    /**************/
    logtype:apache AND apache.status:[500 TO 599]
    |stats count(logtype) as count_500 by apache.geo.isp
    /**************/
    logtype:apache AND apache.resp_len>1000
    |stats count(logtype) as len_1000 by apache.geo.isp
    /**************/
    logtype:apache
    |stats count(logtype) as count_all by apache.geo.isp
    |sort by count_all
    |limit 5
    |join type=left apache.geo.isp [[
    logtype:apache AND apache.status:[400 TO 499]
    |stats count(logtype) as count_400 by apache.geo.isp
    ]]
    |join type=left apache.geo.isp [[
    logtype:apache AND apache.status:[500 TO 599]
    |stats count(logtype) as count_500 by apache.geo.isp
    ]]
    |join type=left apache.geo.isp [[
    logtype:apache AND apache.resp_len>1000
    |stats count(logtype) as len_1000 by apache.geo.isp
    ]]

append

将子管道结果附加在主管道结果之后,可以将不同类型数据进行关联分析,子查询 * 主管道统计大前天的平均响应值,append命令中子管道统计昨天的平均值,其结果合并在一张表中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
starttime="-3d/d" endtime="-2d/d" * 
|stats avg(apache.resp_len)
|eval day="the day before yesterday"
|append [[
starttime="-1d/d" endtime="now/d" *
|stats avg(apache.resp_len)
|eval day="yesterday"
]]
/**************/
starttime="-1d/d endtime=now/d"
|bucket timestamp span=1h as ts
|eval time=formatdate(ts,"HH")
|stats count() as _count by time
|eval group="yesterday"
|append [[
starttime="now/d endtime=now"
|bucket timestamp span=1h as ts
|eval time=formatdate(ts,"HH")
|stats count() as _count by time
|eval group="today"
]]

autoregress

一般用作行与行之间的值计算,计算指标数据,如环比, * 按小时统计事件数,并计算出当前小时和上个小时的事件变化率

1
2
3
4
5
6
7
8
9
10
11
* |bucket timestamp span=1h as ts 
|stats count() as count_ by ts
|autoregress count_ as last_count p=1
|eval a=(last_count-count_) / count_
|eval change_rate=format("%.3f%%",(last_count - count_)*100 / count_)
/**************/
starttime="-2h/h" endtime="now/h" *
|bucket timestamp span=10m as ts
|stats count() as count_app by ts \
|eval time=formatdate(ts)
|autoregress count_app p=3

lookup

外部导入生成新字段 * csv 文件字段host,user,department将搜索结果的hostname字段与csv文件的host进行关联

1
2
3
logtype:apache 
|stats count() by hostname
|lookup user,department /data/rizhiyi/share/host_user.csv on hostname=host

map

引用上次搜索结果 * 列出日志数最多的三种logtype他们各自最大的日志文本长度

1
2
3
4
5
* |stats count() by logtype 
|limit 3
|rename logtype as type
|map "logtype:$type$
|stats max(raw_message_length)"

parse

搜索时抽取字段
* 从原文中抽取IP地址,得到新的字段ip_addr分组并计算appname的个数

1
2
* |parse "(?<ip_addr>\d+\.\d+\.\d+\.\d+)" 
|stats count(appname) by ip_addr

parsedate

时间处理

1
2
3
|makeresults count=1 
|eval pd=parsedate("28/04/2019:12:01:01","dd/MM/yyyy:HH:mm:ss")
|eval fd=formatdate(bd,"yyyy/dd/MM HH:mm:ss")

esma智能运维

对某一个字段的未来值进行预测
* 统计过去一年的每天平均延迟,推测接下来一个月网络延迟

1
2
3
* |bucket timestamp span=1d as ts 
|stats avg(network.latency) as latency by ts
|esma latency timefield=ts period=7 futurecount=30

  • 主机内存使用预测
    1
    2
    3
    4
    appname:top_info_system_stats AND ip:192.168.10.1 
    |bucket timestamp span=10m as ts
    |stats avg(json.Mem.used_percent) as mem_use by ts
    |esma mem_use timefield=ts

movingavg

计算移动平均值
* 以分钟为单位统计apache返回apache_len长度的和,以10为窗口计算移动平均值,得到每分钟的响应长度和平滑后的值

1
2
3
4
logtype:apache 
|bucket timestamp span=1m as ts
|stats sum(apache.resp_len) as sum_len by ts
|movingavg sum_len,10 as moving_avg_resp_len

rollingavg

计算移动标准差 * 以时间分组算出apache返回的reponse长度的和,以10为窗口计算rolling的标准差,观察resp_len的波动情况

1
2
3
logtype:apache 
|stats sum(apache.resp_len) as sum_resp_len by timestamp
|rollingstd sum_resp_len,10 as resp_len_rolling_std

transpose

将查询的表格数据进行行列转换

1
2
* |stats count() as cnt by apache.method,apache.status 
|transpose row=apache.method column=apache.status valuefield=cnt


SPL
https://anyu967.github.io/posts/546a1914.html
作者
anyu967
发布于
2019年11月20日
许可协议