logstash
logstash
logstash架构
logstash部署(二进制方式)
1.解压
tar -zxf logstash-7.xx.x-linux-x86_64.tar.gz -C /opt/software
2.软连接
cd /opt/software && ln -sv logstash-7.xx.x-linux-x86_64.tar.gz logstash
3.环境变量
cat <<EOF>> /etc/profile.d/elk.sh
export LOGSTASH_HOME=/opt/software/logstash
export PATH=$PATH:$LOGSTASH_HOME/bin
EOF
source /etc/profile.d/elk.sh
4.测试案例
vim 01-stdin-to-stdout.conf
input {
stdin {}
}
output {
stdout {}
}
5.运行案例
logstash -f 01-stdin-to-stdout.conf
yum 启动 logstash
logstash -t -f /path/to/logstash-conf-file
-t 测试,正常启动不指定
-f 指定文件
用于测试,在终端输入内容,查看输出是否正常
vim 01-stdin-to-stdout.conf
input {
stdin {}
}
output {
stdout {}
}
input
input-file
创建一个 Logstash 配置文件 logstash.conf
vim logstash.conf
# 从文件收集日志
input {
# file插件
file {
# 类似打标签
type => "file"
# 指定收集的路径
path => "/var/log/nginx/access.log"
# 指定文件的读取位置,仅在“.sincedb*”文件中没有记录时生效。默认值end
start_position => "beginning"
sincedb_path => "/dev/null"
}
}
input-file中常用的配置项
discover_interval
logstash 每隔多久去检查一次被监听的 path 下是否有新文件。默认值是 15 秒。
exclude
不想被监听的文件可以排除出去,这里跟 path 一样支持 glob 展开
close_older
一个已经监听中的文件,如果超过这个值的时间内没有更新内容,就关闭监听它的文件句柄。默认是 3600 秒,即一小时。
ignore_older
在每次检查文件列表的时候,如果一个文件的最后修改时间超过这个值,就忽略这个文件。默认是 86400 秒,即一天。
sincedb_path
如果你不想用默认的 $HOME/.sincedb。可以通过这个配置定义 sincedb 文件到其他位置。
logstash会将以读取的文件名和位置记录到sincedb中,避免重复处理文件
sincedb_write_interval
logstash 每隔多久写一次 sincedb 文件,默认是 15 秒。
stat_interval
logstash 每隔多久检查一次被监听文件状态(是否有更新),默认是 1 秒。
start_position
logstash 从什么位置开始读取文件数据,默认是结束位置,也就是说 logstash 进程会以类似 tail -F 的形式运行。如果你是要导入原有数据,把这个设定改成 “beginning”,logstash 进程就从头开始读取,类似 less +F 的形式运行。
将 sincedb_path 定义为 /dev/null,则每次重启自动从头开始读(适用于重复测试)
input-tcp
# 从tcp收集日志
# 与filebeat类似,可以收集交换机等的日志
input {
tcp {
# 类似打标签
type => "tcp"
port => 8000
}
}
input-http
# 从http收集日志
input {
http {
# 类似打标签,指定类型
type => "tcp"
port => 8000
}
}
input-redis
# 从redis收集日志
input {
redis {
# 类似打标签
type => "redis"
# 指定redis的key的类型
data_type => "list"
# redis数据库编号,默认0
db => 5
# 指定数据库IP,默认localhost
host => "10.0.0.1"
# 指定redis的端口
port => 6379
# 指定redis认证密码
password => "password"
# 指定从redis的哪个key取数据
key => "hello"
}
}
filter
filter-gork
filter {
# grok将非结构化日志数据解析为结构化和可查询的数据
grok {
# 指定正则
match => {
# message字段中的日志行将应用默认的apache日志
"message" => "%{COMBINEDAPACHELOG}"
}
# 移除指定字段
remove_field => [ "host", "log", "@version", "agent" ]
# 添加指定字段
add_fielad => {
# 在新字段和其内容中均引用现有日志中的字段,生成新的内容
"foo_%{somefield}" => "Hello world, from %{host}"
# 添加新的字段"new_field",其内容为"some_new_text"
"new_field" => "some_new_text"
}
# 添加tag,即添加字段tag
add_tag => [ "tag1", "tag2" ]
# 移除tag
remove_tag => ["tag1"]
# 创建插件的唯一ID,不创建系统自动生成
# 用于在系统中有多个grok时做区分
id => "sometext"
}
filter-date
# 修改@timestamp的时间为为日志的实际生成时间
date {
# 用日志中的logdate字段记录的时间,覆盖@timestamp的时间
# logstash的输出时间可能会错8小时,但写入es的时间是准确的
match => ["logdate", "dd/MMM/yyyy:HH:mm:ss +0800"]
# 将时区字段设置为UTC,写入es的时间不准确
timezone => "UTS"
# 这样准确
timezone => "Asia/Shanghai"
# 将匹配到的时间字段解析后存储到目标字段,若不指定,默认字段为"@timestamp"
target => "my-timestamp"
}
filter-geoip 分析日志中IP来源
geoip {
# 指定基于哪个字段分析IP地址
source => "clientip"
# 只显示指定字段
fields => ["city_name", "country_name", "ip"]
# 自定义geoip字段名称,默认字段是geoip
# 当日志中有源IP和目标IP时,可以分开记录
target => "my-src_ip"
}
filter-useragent 分析日志中的设备类型
useragent {
# 指定要分析的包含设备信息的字段
source => "http_user_agent"
# 将分析后的数据存储在指定字段中,不指定,则存储在tartget字段中
target => "my-useragent"
}
filter-mutate 对字段执行转变,可以重命名、移除、替换和修改日志中的字段
转变要按顺序进行,通过使用单独的mutate块来控制顺序
有修改的选项尽量写下边
mutate {
# 分割字段
split => { "message" => "|" }
# 添加字段,其中引用的变量
add_field => {
"user_id" => "%{[message][1]}"
"action" => "%{[message][2]}"
"svip" => "%{[message][3]}"
}
}
mutate {
# 去除字段前后的空格
strip => ["svip"]
}
mutate {
# 将指定字段转换为相应的数据类型
convert => {
"user_id" => "integer"
"svip" => "boolean"
}
}
mutate {
# 重命名字段
rename => {"shortHostname" => "hostname"}
}
# 根据type值执行分支
if [type] == "sometext" {
mutate {
...
}
geoip {
...
}
useragent {
...
}
}
}
output
output-elasticsearch
# 输出到es
output {
elasticsearch {
hosts => ["http://esIP:9200"]
# 指定索引,该索引与kibana中的索引模板匹配,则会引用模板中的规则
index => "sometext-%{+YYYY.MM.dd}"
}
}
output-redis
# 输出到redis
output {
redis {
host => ["http://esIP:9200"]
port => "6379"
db => 10
password => "password"
# 指定写入数据的key的类型
data_type => "list"
# 指定写入的key的名称
key => "my-key"
}
}
outpu-file
# 输出到file
output {
file {
path => "/path/to/file"
}
}
grok语法说明
grok是一个文本解析工具,用于从非结构化的日志数据中提取字段,并将其转换为结构化的数据
grok使用正则和模式来匹配日志行,内置120种匹配模式
语法
%{PATTERN:fieldName}
PATTERN 是用于匹配日志行的正则表达式模式,fieldName 是您要将匹配部分提取为的字段名。
例子
假设日志行如下,我们希望从日志行中提取日期时间和日志级别,并将它们作为字段存储。
2023-07-19 10:30:01,123 - INFO - This is a log message.
可以使用以下 Grok 模式:
%{DATESTAMP:timestamp} - %{LOGLEVEL:logLevel} - %{GREEDYDATA:message}
解释:
* %{DATESTAMP:timestamp} 匹配日期时间格式,将匹配部分存储为 timestamp 字段。
* - 匹配短横线 - 字符。
* %{LOGLEVEL:logLevel} 匹配日志级别,将匹配部分存储为 logLevel 字段。
* - 匹配短横线 - 字符。
* %{GREEDYDATA:message} 匹配剩余的任意文本,并将匹配部分存储为 message 字段。
最终,Logstash 将解析日志行并将提取的字段存储为结构化数据,类似于以下格式:
{
"timestamp": "2023-07-19 10:30:01,123",
"logLevel": "INFO",
message": "This is a log message."
}
在 Logstash 的配置文件中,您可以使用 grok 过滤器插件来应用 Grok 模式。例如:
filter {
grok {
match => {
"message" => "%{DATESTAMP:timestamp} - %{LOGLEVEL:logLevel} - %{GREEDYDATA:message}"
}
}
}
自定义grok匹配模式
filter {
grok {
# 自定义匹配模式目录,名称随意
# 具体的匹配模式写在该目录下的文件中
patterns_dir => "/path/to/patterns"
# 将日志行中的字段提取为新的字段
match => {
"message" => "%{SYSLOGBASE} %{POSTFIX_QUEUEID:queue_id}: %{GREEDYDATA:syslog_message}"
}
}
}
vim /path/to/patterns/custom-pattern
# 匹配的字段名和具体的匹配正则
POSTFIX_QUEUEID [0-9A-F]{10,11}
logstash内置匹配模式位置
/usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/logstash-patterns-core-4.3.1/patterns/legacy/grok-patterns
filebeat和logstash打通,input模块基于beats插件
filebeat配置
filebeat.inputs:
- type: tcp
# filebeat开启9000端口,接收日志
host: "0.0.0.0:9000"
output.logstash:
# 输出到logstash的5044端口
hosts: ["10.0.0.101:5044"]
logstash配置
input{
# 从elastic beats框架接收事件
beats {
# logstash从本机的5044端口接收filebeat传来的日志
port => 5044
}
}
output {
stdout {}
}
logstash多实例案例
logstash -f /path/to/logstash.conf --path.data /other/path/to/logstash.conf
--path.data 指定不同的配置文件启动
mutate 数据准备
脚本模拟日志生成
vim generate_log.py
#!/usr/bin/env python
# _*_ coding: UTF-8 _*_
import datetime
import random
import logging
import time
import sys
LOG_FORMAT = "%{levelname}s %{asctime}s [com.hello.%{module}s] - %{message}s"
DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
logging.basicConfig(level=logging.INFO, format=LOG_FORMAT, datefmt=DATE_FORMAT, filename=sys.argv[1], filemode='a',)
actions = ["浏览商品", "加购物车", "提交订单", "领券", "用券", "搜索"]
while True:
time.sleep(random.randint(1, 5))
user_id = random.randint(1, 10000)
# 取浮点数
price = round(random.uniform(1000,300000),2)
action = random.choice(actions)
svip = random.choice([0,1])
logging.info("DAU|{0}|{1}|{2}|{3}".format(user_id, action, svip, price))
python generate_log.py /tmp/my.log
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了