写入处理器使用场景

写入处理器可在日志数据写入Logstore前对数据进行处理,例如字段修改,字段解析,数据过滤和数据脱敏。本文介绍写入处理器的配置方法,以及使用场景示例。

前提条件

已创建Project、标准型Logstore并完成日志采集配置。具体操作,请参见创建项目Project创建Logstore数据采集概述

使用场景

假如要从原始日志中截取三个字段:request_methodrequest_uristatus。您可按照以下步骤操作。

原始日志

body_bytes_sent: 22646
host: www.example.com
http_protocol: HTTP/1.1
remote_addr: 192.168.31.1
remote_user: Elisa
request_length: 42450
request_method: GET
request_time: 675
request_uri: /index.html
status: 200
time_local: 2024-12-04T13:47:54+08:00

操作步骤

  1. 创建写入处理器

    1. 登录日志服务控制台

    2. 在Project列表区域,单击目标Project。

    3. 在左侧导航栏选择资源 > 数据处理器

    4. 写入处理器页签,单击创建。在创建处理器面板配置处理器名称SPL处理失败,配置完成后单击确定。参数说明如下。

      参数

      说明

      处理器名称

      输入处理器的名称,例如nginx-logs-text

      描述

      处理器的描述。

      SPL

      输入SPL语句。例如:

      * | project request_method, request_uri, status

      更多信息,请参见SPL指令

      处理失败

      SPL处理失败后的行为,支持:

      • 保留原始数据

      • 丢弃原始数据

      说明
      • 这里处理失败仅指SPL执行失败,例如数据不合法导致算子执行异常。不包含SPL语法错误的场景。

      • 如果SPL语法配置错误导致解析失败,默认会保留原始数据。

  2. 将写入处理器应用到Logstore。

    1. 在目标Project页面,在左侧导航栏单击日志存储,然后将鼠标悬浮在目标Logstore上,单击修改

    2. 在Logstore属性页面,单击右上角修改,在编辑状态下配置写入处理器,选择需要关联的写入处理器,然后单击右上角的保存image

      说明

      关联写入处理器,仅对增量日志生效,生效时间1分钟左右。

  3. 在Logstore主页面,单击查询/分析,查询采集到的日志。image

更多使用场景示例

  • 字段修改

    通过projectproject-awayproject-renameextend等 SPL 指令可以对数据的字段进行增删改处理。例如原始日志为:

    body_bytes_sent: 22646
    host: www.example.com
    http_protocol: HTTP/1.1
    referer: www.example.com
    remote_addr: 192.168.31.1
    remote_user: Elisa
    request_length: 42450
    request_method: PUT
    request_time: 675
    request_uri: /request/path-1/file-6?query=123456
    status: 200
    time_local: 2024-12-04T13:47:54+08:00

    使用场景

    需求描述

    SPL语句

    结果

    保留特定字段

    仅保留如下三个字段:

    • request_method

    • request_uri

    • status

    * | project request_method, request_uri, status
    request_method: PUT
    request_uri: /request/path-1/file-6?query=123456
    status: 200

    仅保留如下三个字段,且需要对结果字段重命名:

    • request_method重命名为method

    • request_uri重命名为uri

    • status

    * | project method=request_method, uri=request_uri, status
    method: PUT
    uri: /request/path-1/file-6?query=123456
    status: 200

    保留所有request_开头的字段。

    * | project -wildcard "request_*"
    request_length: 42450
    request_method: PUT
    request_time: 675
    request_uri: /request/path-1/file-6?query=123456

    删除特定字段

    删除如下字段:

    • http_protocol

    • referer

    • remote_addr

    • remote_user

    * | project-away http_protocol, referer, remote_addr, remote_user
    body_bytes_sent: 22646
    host: www.example.com
    request_length: 42450
    request_method: PUT
    request_time: 675
    request_uri: /request/path-1/file-6?query=123456
    status: 200
    time_local: 2024-12-04T13:47:54+08:00

    删除所有request_开头的字段。

    * | project-away -wildcard "request_*"
    body_bytes_sent: 22646
    host: www.example.com
    http_protocol: HTTP/1.1
    referer: www.example.com
    remote_addr: 192.168.31.1
    remote_user: Elisa
    status: 200
    time_local: 2024-12-04T13:47:54+08:00

    新增字段

    新增app字段,值固定为test-app

    * | extend app='test-app'
    app: test-app
    body_bytes_sent: 22646
    host: www.example.com
    http_protocol: HTTP/1.1
    referer: www.example.com
    remote_addr: 192.168.31.1
    remote_user: Elisa
    request_length: 42450
    request_method: PUT
    request_time: 675
    request_uri: /request/path-1/file-6?query=123456
    status: 200
    time_local: 2024-12-04T13:47:54+08:00

    新增request_query字段,值需要从request_uri中进行提取。

    * | extend request_query=url_extract_query(request_uri)
    body_bytes_sent: 22646
    host: www.example.com
    http_protocol: HTTP/1.1
    referer: www.example.com
    remote_addr: 192.168.31.1
    remote_user: Elisa
    request_length: 42450
    request_method: PUT
    request_query: query=123456
    request_time: 675
    request_uri: /request/path-1/file-6?query=123456
    status: 200
    time_local: 2024-12-04T13:47:54+08:00

    修改字段名

    time_local重命名为time

    * | project-rename time=time_local
    body_bytes_sent: 22646
    host: www.example.com
    http_protocol: HTTP/1.1
    referer: www.example.com
    remote_addr: 192.168.31.1
    remote_user: Elisa
    request_length: 42450
    request_method: PUT
    request_time: 675
    request_uri: /request/path-1/file-6?query=123456
    status: 200
    time: 2024-12-04T13:47:54+08:00

    修改字段值

    request_uri字段进行处理,仅保留路径部分,丢掉参数部分。

    * | extend request_uri=url_extract_path(request_uri)

    或者

    * | extend request_uri=regexp_replace(request_uri, '\?.*', '')
    body_bytes_sent: 22646
    host: www.example.com
    http_protocol: HTTP/1.1
    referer: www.example.com
    remote_addr: 192.168.31.1
    remote_user: Elisa
    request_length: 42450
    request_method: PUT
    request_time: 675
    request_uri: /request/path-1/file-6
    status: 200
    time_local: 2024-12-04T13:47:54+08:00
  • 字段解析

    通过parse-regexpparse-jsonparse-csv等 SPL 指令,以及 SQL 中的正则、JSON 等处理函数,可以实现对数据的字段解析和提取。

    使用场景

    原始数据

    需求描述

    SPL语句

    结果

    正则解析

    content: 192.168.1.75 - David [2024-07-31T14:27:24+08:00] "PUT /request/path-0/file-8 HTTP/1.1" 819 21577 403 73895 www.example.com www.example.com "Mozilla/5.0 (Windows NT 5.2; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1"

    通过正则表达式对 Nginx 访问日志进行字段提取,并丢弃原来的content字段。

    * 
    | parse-regexp content, '(\S+)\s-\s(\S+)\s\[(\S+)\]\s"(\S+)\s(\S+)\s(\S+)"\s(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\S+)\s(\S+)\s"(.*)"' as remote_addr, remote_user, time_local, request_method, request_uri, http_protocol, request_time, request_length, status, body_bytes_sent, host, referer, user_agent
    | project-away content
    body_bytes_sent: 73895
    host: www.example.com
    http_protocol: HTTP/1.1
    referer: www.example.com
    remote_addr: 192.168.1.75
    remote_user: David
    request_length: 21577
    request_method: PUT
    request_time: 819
    request_uri: /request/path-0/file-8
    status: 403
    time_local: 2024-07-31T14:27:24+08:00
    user_agent: Mozilla/5.0 (Windows NT 5.2; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1
    request_method: PUT
    request_uri: /request/path-0/file-8
    status: 200

    request_uri字段中提取出file-8部分,并命名为file字段。

    * | extend file=regexp_extract(request_uri, 'file-.*')

    file: file-8
    request_method: PUT
    request_uri: /request/path-0/file-8
    status: 200

    JSON解析

    headers: {"Authorization": "bearer xxxxx", "X-Request-ID": "29bbe977-9a62-4e4a-b2f4-5cf7b65d508f"}

    headers字段进行 JSON 解析,并丢弃原来的headers字段。

    *
    | parse-json headers
    | project-away headers

    Autorization: bearer xxxxx
    X-Request-ID: 29bbe977-9a62-4e4a-b2f4-5cf7b65d508f

    headers中提取部分字段,例如提取出Authorization字段,并命名为token

    * | extend token=json_extract_scalar(headers, 'Authorization')

    headers: {"Authorization": "bearer xxxxx", "X-Request-ID": "29bbe977-9a62-4e4a-b2f4-5cf7b65d508f"}
    token: bearer xxxxx

    request: {"body": {"user_id": 12345, "user_name": "Alice"}}

    request字段中的body子字段进行JSON解析。

    * | parse-json -path='$.body' request
    request: {"body": {"user_id": 12345, "user_name": "Alice"}}
    user_id: 12345
    user_name: Alice

    分隔符解析

    content: 192.168.0.100,"10/Jun/2019:11:32:16,127 +0800",www.example.com

    按照逗号将字段进行分割,并丢弃原来的content字段。

    *
    | parse-csv -quote='"' content as ip, time, host
    | project-away content
    host: www.example.com
    ip: 192.168.0.100
    time: 10/Jun/2019:11:32:16,127 +0800
    content: 192.168.0.100||10/Jun/2019:11:32:16,127 +0800||www.example.com

    使用||作为分隔符,将字段进行分割,并丢弃原来的content字段。

    *
    | parse-csv -delim='||' content as ip, time, host
    | project-away content
    host: www.example.com
    ip: 192.168.0.100
    time: 10/Jun/2019:11:32:16,127 +0800

  • 数据过滤

    通过where指令可以对数据进行过滤。

    需要特别注意的是,在SPL处理过程中,会默认将所有原始字段当做文本来进行处理,因此如果需要进行数值操作,应当先通过类型转换函数函数进行类型转换。

    原始数据

    需求描述

    SPL语句

    结果

    request_id: ddbde824-7c3e-4ff1-a6d1-c3a53fd4a919
    status: 200
    
    ---
    
    request_id: 7f9dad20-bc57-4aa7-af0e-436621f1f51d
    status: 500

    仅保留status200的数据。

    * | where status='200'

    或者

    * | where cast(status as bigint)=200
    request_id: ddbde824-7c3e-4ff1-a6d1-c3a53fd4a919
    status: 200
    request_id: ddbde824-7c3e-4ff1-a6d1-c3a53fd4a919
    status: 200
    
    ---
    
    request_id: 7f9dad20-bc57-4aa7-af0e-436621f1f51d
    status: 500
    error: something wrong

    仅保留不存在error字段的数据。

    * | where error is null
    request_id: ddbde824-7c3e-4ff1-a6d1-c3a53fd4a919
    status: 200

    仅保留存在error字段的数据。

    * | where error is not null
    request_id: 7f9dad20-bc57-4aa7-af0e-436621f1f51d
    status: 500
    error: something wrong
    method: POST
    request_uri: /app/login
    
    ---
    
    method: GET
    request_uri: /user/1/profile
    status: 404
    
    ---
    
    method: GET
    request_uri: /user/2/profile
    status: 200

    仅保留request_uri/user/开头的数据。

    * | where regexp_like(request_uri, '^\/user\/')
    method: GET
    request_uri: /user/1/profile
    status: 404
    
    ---
    
    method: GET
    request_uri: /user/2/profile
    status: 200

    保留request_uri/user/开头,且status200的数据。

    * | where regexp_like(request_uri, '^\/user\/') and status='200'
    method: GET
    request_uri: /user/2/profile
    status: 200
  • 数据脱敏

    通过 SPLextend指令结合正则处理、字符串处理、URL处理等 SQL 函数,可以实现数据的脱敏操作。

    使用regexp_replace函数对字段的值进行正则替换的时候,支持使用捕获组。在替换值的时候,可以使用\1\2… 分别表示第一个、第二个…捕获组的值。

    例如 regexp_replace('192.168.1.1', '(\d+)\.(\d+)\.\d+\.\d+', '\1.\2.*.*')结果为192.168.*.*

    原始数据

    需求描述

    SPL语句

    结果

    request_uri: /api/v1/resources?user=123&ticket=abc
    status: 200

    request_uri参数中包含一些敏感信息,需要移除。

    * | extend request_uri=url_extract_path(request_uri)

    或者

    * | extend request_uri=regexp_replace(request_uri, '\?.*', '')
    request_uri: /api/v1/resources
    status: 200
    client_ip: 192.168.1.123
    latency: 100

    对 IP 做脱敏处理,将中间两部分替换为星号。

    * | extend client_ip=regexp_replace(client_ip, '(\d+)\.\d+\.\d+\.(\d+)', '\1.*.*.\2')
    client_ip: 192.*.*.123
    latency: 100
    sql: SELECT id, name, config FROM app_info WHERE name="test-app"
    result_size: 1024

    sql字段中可能包含一些敏感信息,因此需要仅保留操作以及对应的表名即可。

    *
    | extend table=regexp_extract(sql, '\bFROM\s+([^\s;]+)|\bINTO\s+([^\s;]+)|\bUPDATE\s+([^\s;]+)', 1)
    | extend action=regexp_extract(sql,'\b(SELECT|INSERT|UPDATE|DELETE|CREATE|DROP|ALTER)\b', 1)
    | project-away sql
    action: SELECT
    table: app_info
    result_size: 1024