[TOC]
Logrotate 日志管理工具
logrotate 是一个 Linux 零碎默认装置了的日志文件管理工具,用来把旧文件轮转、压缩、删除,并且创立新的日志文件。咱们能够依据日志文件的大小、天数等来转储,便于对日志文件治理。
默认 logrotate 是在每天凌晨 3 点多被 anacron 调用执行.
具体调用流程剖析能够见 4. Shell 篇.md#anacron 周期命令调度程序
日志管理工具
logrotate [选项] < 配置文件 >
选项
# 罕用
-d, --debug # 调试模式,仅输入操作步骤,并不理论执行。隐式蕴含 -v 参数
-f, --force # 强制执行转储(logrotate 会依据状态文件, 主动断定是否有必要执行), 若配置文件刚批改完要马上执行倡议应用该参数.
-s, --state=statefile # 应用指定的状态文件(而非默认的),对于运行在不同用户状况下有用
-v, --verbose # 显示转储过程的详细信息
# 不罕用
-m, --mail=command # 发送邮件命令而不是用‘/bin/mail' 发
文件
/etc/logrotate.conf # 默认配置文件
/var/lib/logrotate.status # 默认状态文件
-
默认配置文件
/etc/logrotate.conf
中个别会有一句include /etc/logrotate.d
用于加载该目录下的所有配置文件.可在
/etc/logrotate.d/
下搁置自定义的配置文件来主动调用. - 默认的状态文件(记录每个解决的日志的最初工夫?)
/var/lib/logrotate.status
参考:
- https://www.linuxprobe.com/co…
- https://www.cnblogs.com/wushu…
配置选项
默认读取的配置 /etc/logrotate.conf
# 触发形式 - 工夫距离
hourly
daily
weekly
monthly
# 触发形式 - 文件大小
size <logsize> # 当日志文件达到指定的大小时才转储(例如 10(字节), 100k,4M, 1G
maxsize <size> # 与工夫距离一起配置, 当日志文件超过该 maxsize 时, 即便未到指定工夫距离也会轮转
minsize <size> # 与工夫距离一起配置, 若日志文件未超过该 minsize 时, 即便达到指定工夫距离也不会轮转.
# 对旧日志操作形式(默认策略应该是重命名原日志文件)
默认形式 # 批改日志文件名(理论是批改所属目录 inode 中的信息), 若该文件已被过程关上, 通常须要配置 postrotate 发送信号给该过程以从新关上日志文件.
copytruncate # 用于还在关上中的日志文件,把以后日志备份并截断,是先拷贝再清空的形式,拷贝和清空之间有一个时间差,可能会失落局部日志数据
nocopytruncate # 备份日志文件然而不截断
# 压缩
compress # 压缩 (gzip) 日志文件的所有非以后版本
nocompress # (默认)不压缩
delaycompress # 本次转储的日志在下一次转储时才压缩.
nodelaycompress # (默认)不提早压缩
# 邮件
mail <mail> # 转储的日志发送到指定邮箱
nomail # (默认)不发送转储的日志文件到邮箱
# 错误处理
errors <mail> # 转储时的错误信息发送到指定邮箱
missingok # 如果日志文件失落,不要显示谬误
# 空文件解决
notifempty # 如果日志文件为空,则不轮换日志文件(即疏忽空文件).
ifempty # (默认)即便空文件也转储
# 寄存目录
olddir <dir> # 转储后的日志放在指定目录下
noolddir # (默认)转储后的日志放在和以后日志文件同一个目录下
# 转储日志命名
dateext # 指定转储后的日志文件以以后日期为格局结尾,如 access.log-20200426.gz.
# 默认是以自增序号, 比方 messages -> messages.1 -> messages.2
dateformat <dateformat> # 配合 dateext 应用,紧跟在下一行呈现,定义日期格局,只反对 %Y %m %d %H %s 这 5 个参数(%s 是工夫戳)
# hourly 默认应用工夫格局: -%Y%m%d%H
# daily,weekly,monthly 默认应用工夫格局: -%Y%m%d
# 示例: dateformat -%Y%m%d%s
# 保留转储文件数量
rotate <n> # 保留转储后的日志文件数量, 0 指没有备份(轮转后马上删除旧日志), n 指保留 n 个备份
# 创立新日志
create <mode> <user> <group> # 轮换原始文件并创立具备指定权限、用户和组的新文件, 示例: create 700 root root
nocreate # (默认)不被动创立新的日志文件
# 脚本
sharedscripts # 对于整个日志组只运行一次脚本
prerotate # 引入一个在日志被轮换前执行的脚本, 须要和 endscript 严格配置. 关键字必须独自一行.
postrotate # 引入一个在日志被轮换后执行的脚本, 须要和 endscript 严格配置. 关键字必须独自一行.
endscript # 标记 prerotate 或 postrotate 脚本的完结, 关键字必须独自一行.
示例
nginx 示例
/data/nginx/logs/*log {
daily
rotate 32
missingok
notifempty
compress
delaycomporess
dateext
sharedscripts
postrotate
/bin/kill -USR1 $(cat /var/run/nginx.pid 2>/dev/null) 2>/dev/null || :
endscript
}
轮转完后日志会从
/data/nginx/logs/access.log
变为/data/nginx/logs/access.log-20200426.gz
, 之类的日期是个示例.
可通过手动执行 (指定配置文件) 来调用:
logrotate /path/to/nginx_logrotate
日志轮转的机制
此处不探讨压缩等的后续操作.
该局部内容来自: https://www.lightxue.com/how-…
若 inode 局部不了解, 可查看原文链接或查看笔记 3. 系统管理篇.md# 文件、目录与 inode(i 节点))
计划 1:create
默认计划没有名字,权且叫它 create 吧。因为这个计划会创立一个新的日志文件给程序输入日志,而且第二个计划名 copytruncate 是个配置项,与 create 配置项是互斥的。
这个计划的思路是重命名原日志文件,创立新的日志文件。具体步骤如下:
- 重命名程序以后正在输入日志的程序。因为重命名只会批改目录文件的内容,而过程操作文件靠的是 inode 编号,所以并不影响程序持续输入日志。
- 创立新的日志文件,文件名和原来日志文件一样。尽管新的日志文件和原来日志文件的名字一样,然而 inode 编号不一样,所以程序输入的日志还是往原日志文件输入。
- 通过某些形式告诉程序,从新关上日志文件。程序从新关上日志文件,靠的是文件门路而不是 inode 编号,所以关上的是新的日志文件。
什么形式告诉程序我从新关上日志呢,简略粗犷的办法是杀死过程从新关上。很多场景这种作法会影响在线的服务,于是有些程序提供了从新关上日志的接口,比方能够通过信号告诉 nginx。各种 IPC 形式都能够,前提是程序本身要反对这个性能。
有个中央值得一提,一个程序可能输入了多个须要滚动的日志文件。每滚动一个就告诉程序从新关上所有日志文件不太划得来。有个 sharedscripts
的参数,让程序把所有日志都重命名了当前,只告诉一次。
计划 2:copytruncate
如果程序不反对从新关上日志的性能,又不能粗犷地重启程序,怎么滚动日志呢?copytruncate 的计划出场了。
这个计划的思路是把正在输入的日志拷 (copy) 一份进去,再清空 (trucate) 原来的日志。具体步骤如下:
- 拷贝程序以后正在输入的日志文件,保留文件名为滚动后果文件名。这期间程序照常输入日志到原来的文件中,原来的文件名也没有变。
- 清空程序正在输入的日志文件。清空后程序输入的日志还是输入到这个日志文件中,因为清空文件只是把文件的内容删除了,文件的 inode 编号并没有发生变化,变动的是元信息中文件内容的信息。
后果上看,旧的日志内容存在滚动的文件里,新的日志输入到空的文件里。实现了日志的滚动。
这个计划有两个乏味的中央。
- 文件清空并不影响到输入日志的程序的文件表里的文件地位信息,因为各过程的文件表是独立的。那么文件清空后,程序输入的日志应该接着之前日志的偏移地位输入,这个地位之前会被
\0
填充才对。但实际上 logroate 清空日志文件后,程序输入的日志都是从文件开始处开始写的。这是怎么做到的?这个问题让我纠结了很久,直到某天灵光一闪,这不是 logrotate 做的,而是成熟的写日志的形式,都是用O_APPEND
的形式写的。如果程序没有用O_APPEND
形式关上日志文件,变会呈现 copytruncate 后日志文件后面会被一堆\0
填充的状况。 - 日志在拷贝完到清空文件这段时间内,程序输入的日志没有备份就清空了,这些日志不是丢了吗?是的,copytruncate 有失落局部日志内容的危险。所以能用 create 的计划就别用 copytruncate。所以很多程序提供了告诉我更新关上日志文件的性能来反对 create 计划,或者本人做了日志滚动,不依赖 logrotate。
指定每日 0 点转储文件
形式 1: 批改 anacrontab 调用 logrotate 的机会(极其不举荐, 会影响其余服务的调用机会)
形式 2: crontab 手动定义配置文件(目前集体举荐)
-
创立配置文件
/etc/logrotate_daily0.conf
dateext missingok notifempty include /etc/logrotate_daily0.d
-
创立目录
/etc/logrotate_daily0.d
次要不要应用默认目录, 否则会被失常的 logrotate 调度执行到
- 在上述目录下创立本人想要的配置文件
-
在 crontab 配置定时工作
0 0 * * * /usr/sbin/logrotate /etc/logrotate_daily0.conf &> /dev/null
一键脚本
cat > /etc/logrotate_daily0.conf <<'EOF'
dateext
rotate 7
missingok
notifempty
include /etc/logrotate_daily0.d
EOF
mkdir /etc/logrotate_daily0.d
cat >> /var/spool/cron/root <<'EOF'
# 0 点执行日志轮转
0 0 * * * /usr/sbin/logrotate -f /etc/logrotate_daily0.conf &> /dev/null
EOF
crontab /var/spool/cron/root
cat > /etc/logrotate_daily0.d/nginx <<'EOF'
/data/nginx/logs/*.log {
missingok
notifempty
daily
compress
dateext
nocreate
rotate 31
sharedscripts
postrotate
/bin/kill -USR1 $(ps -ef|grep nginx|grep master|grep -v grep|awk '{print $2}') || true
endscript
}
EOF
形式 3: 手动指定每日 logrotate 的调用(不举荐, 会影响其余已配置的日志轮转)
-
移除默认定时配置
mv /etc/cron.daily/logrotate /usr/local/bin/logrotate.sh
-
在 crontab 配置定时工作
0 0 * * * /bin/bash /usr/local/bin/logrotate.sh
Ansi
https://github.com/fidian/ansi
这是一个用于生成 ANSI 转义序列的脚本, 可用于:
- 挪动光标
- 文本加粗
- 增加色彩
- …
下载并应用
wget https://raw.githubusercontent.com/fidian/ansi/master/ansi -O /usr/local/bin/ansi
chmod a+x /usr/local/bin/ansi
ansi -h
示例
# 红色字体, 加粗
ansi --bold --bg-red "请用 root 账户执行本脚本";
echo -n '['; ansi -n --bold --green "DONE"; echo ']';
echo -n '['; ansi --bold --red "ERROR"; echo ']';
expect
expect 是一个自动化交互套件,次要利用于执行命令和程序时,零碎以交互模式要求输出指定字符串,实现交互通信
相干链接:
- expect – 主动交互脚本 (未读)
装置
yum install -y expect
留神 expect 脚本结尾一行是 #!/usr/bin/expect
, 或者在执行时应用 expect < 脚本 >
来执行脚本.
命令
set timeout
设置超时工夫
# -1 示意不限度执行超时工夫
set timeout -1
默认是 30s, 若执行会超过这个工夫, 要留神设置 ” 超时工夫 ”, 防止脚本被强行中断
set
定义变量
set 变量名 变量值
# set password "123456"
puts
输入变量
spanw
交互程序开始前面跟命令或者指定程序
spanw ssh xxx@x.x.x.x
expect "*password"
send "123456\n"
# 进入交互模式
interact
expect
语法
expect "文本匹配"
反对通配符匹配expect eof
期待 spawn 的执行完结
expect "待匹配文本"
send "xxx\r"
expect "* 反对通配符 *"
send "xxx\r"
# 等价于下面两条, 更简洁
expect {"待匹配的文本" { send "xxxx\r"; exp_continue}
"* 反对通配符 *" {send "xxx\r"}
}
# 期待 spawn 的脚本完结
expect eof
exp_continue
在 expect 中屡次匹配就须要用到
expect {"待匹配的文本" { send "xxxx\r"; exp_continue}
"* 反对通配符 *" {send "xxx\r"}
}
send
用于发送指定的字符串信息
expect "xxx"
send "xxx\r"
send_user
用来打印输出 相当于 shell 中的 echo
send_user "echo something"
exit
interact
进入交互模式
关键字
if
流程管制
if {...} {# ...}
lindex
获取数组的第 N 个参数
# 应用 lindex 关键字获取第 N 个参数
set 变量名 [lindex $argv 0]
set 变量名 [lindex $argv 1]
...
# 参数总数
if {$argc < 1} {
send_user "..."
exit
}
file
https://wxnacy.com/2018/05/31…
示例
示例: 一个 expect 脚本的模板
#!/usr/bin/expect
set PASSWORD "ssh 明码"
if {$argc < 1} {
send_user "usage: $argv0 <dir>\n"
exit
}
set srcdir [lindex $argv 0]
if {[file isdirectory "$srcdir"] != 1} {
send_user "not exists dir: $srcdir\n"
exit
}
spawn bash deploy.sh $srcdir
# 这是一个主动输出 ssh 明码的应答
expect {"yes/no" { send "yes\n"; exp_continue}
"password:" {send "${PASSWORD}\n" }
}
expect eof
下面是一个在不应用秘钥状况下实现 rsync 免手动输出明码的解决.
示例: 主动输出 mysql 明码
#!/usr/bin/expect
set password xxxx
set name root
spawn mysql -u $name -p
expect "*password:*"
send "$password\r"
interact
示例: 在 shell 中嵌套 expect
#!/bin/bash
for i in `cat /home/admin/timeout_login.txt`
do
/usr/bin/expect << EOF
spawn /usr/bin/ssh -t -p 22022 admin@$i "sudo su -"
expect {"yes/no" { send "yes\r"}
}
expect {"password:" { send "xxo1#qaz\r"}
}
expect {"*password*:" { send "xx1#qaz\r"}
}
expect "*]#"
send "df -Th\r"
expect "*]#"
send "exit\r"
expect eof
EOF
done