用 fread 先读出来,去掉再 fwrire 覆盖原来的,会不会造成期间写入文件的日志信息?
<?php
$file = '/opt/nginx/log/default.log';
$content = shell_exec('head -n 10 '.$file);
echo $content;
shell_exec('sed -i \'10d\' '.$file);
没办法,只能用shell来实现了
1
jmc891205 2020-05-04 14:44:24 +08:00 via iPhone 3
说说看为什么会有这种需求
可能有更好的解决办法 |
3
littlewing 2020-05-04 14:59:28 +08:00
@frozenway 那为什么要删掉前几行?
|
4
frozenway OP @littlewing 不删掉,下次再读取前十行还是它啊
|
5
ic2y 2020-05-04 15:04:05 +08:00
那为什么不用 fseek
|
6
Jooooooooo 2020-05-04 15:06:17 +08:00
既然是读取分析的需求, 那分析的时候跳过前十行不就行了?
|
7
eason1874 2020-05-04 15:06:50 +08:00
fseek + fgets 分块读取就行了,用不着动文件。
比如一次读 100KB,如果最后一行不完整就留着,下次读取块之后加在前面就行。 |
8
jimmyismagic 2020-05-04 15:12:22 +08:00 2
千万不要多线程处理文件,会乱掉的,哈哈
|
9
sanggao 2020-05-04 15:14:26 +08:00
sed
|
10
frozenway OP |
12
leido 2020-05-04 15:21:49 +08:00
tail -n +11 path_to_file > newfile
mv newfile path_to_file |
14
vk42 2020-05-04 15:27:10 +08:00 via Android
保存上次读完 10 行之后的位置,下次 fseek 不就行了,为啥要费劲删 10 行
|
15
frozenway OP “array_shift — 将数组开头的单元移出数组” ,有没有类似这样的文件出栈的功能函数?
|
17
beastk 2020-05-04 15:31:57 +08:00 via iPhone
按天生成日志不就得了
|
18
ipwx 2020-05-04 15:48:51 +08:00 2
@frozenway 首先必须说明,我没听说过操作系统会提供“删掉文件前多少字节”这种功能。所以大概率楼主你的字面需求是完成不了的。
但是解决方案有很多。比如: 1 、固定文件大小,把整个文件当做一个 circular buffer 用(记满了从尾巴跳到开头再开始写,直接覆盖老的内容)。然后用一个额外的小文件记录你有效的起始指针和尾指针的文职。 2 、不要用行这么大的粒度,粗略一点。比如每 500KB 换一个文件写。文件太多了就把老的文件删掉一个。 3 、上数据库。 4 、模仿数据库,自己用 B+ 树管理每一行的精确位置,自己管理文件被废弃的部分的回收再利用,自己管理文件存储碎片。也就是自己创造一种“数据库”。 |
19
cholerae 2020-05-04 15:50:46 +08:00
日志库不都有设置单个文件大小和 rotate 文件的功能吗?
|
20
cholerae 2020-05-04 15:55:39 +08:00 1
说回你的这个需求本身,有个系统调用是 fallocate,fallocate 支持一个参数叫 FALLOC_FL_PUNCH_HOLE,这个东西支持把指定 fd 的偏移区间的块给释放掉,这样就不占空间了。不过不会改文件的元信息,所以你去 ls 还是看到原本的大小,需要你自己维护一个偏移量。
|
21
miao1007 2020-05-04 15:58:27 +08:00 via iPhone
logstash
|
23
love 2020-05-04 16:59:35 +08:00 via Android
你就不能下次从第 20 行开始读起?每读 10 行就复制一整个上 G 的文件,这个效率是嫌服务器负载太低了吗
|
24
winglight2016 2020-05-04 17:21:40 +08:00
虽然我没用过 php,但是日志分析这么基础的需求,不用再自己造轮子了吧?
|
25
julyclyde 2020-05-04 17:25:47 +08:00 7
这是一个很典型的
自行分析了需求然后给出错误解方案 然后上网问怎么实现这个错误方案 的案例 |
26
myqoo 2020-05-04 17:25:48 +08:00
正好写过完全相同的案例~ 每隔一段时间执行就可以:
logtime=$(date "+%Y-%m-%d-%H-%M-%S") mv 日志路径 备份目录 /$logtime.log touch 日志路径 nginx -s reopen |
27
hstdt 2020-05-04 17:25:50 +08:00 via iPhone
要是我来做,我可能会使用 sqlite😉
|
28
ETiV 2020-05-04 17:27:27 +08:00 via iPhone
mkfifo ?
|
29
asilin 2020-05-04 17:43:53 +08:00
很简单,用 sed -i -c 参数就可以完成,具体参见下面的链接:
https://stackoverflow.com/questions/36930913/extra-null-characters-when-sed-edit-the-file-in-place-which-under-wirting |
30
banxiaobu 2020-05-04 18:08:08 +08:00
我更感兴趣的是这个是什么样的背景需要这么玩
|
31
burringcat 2020-05-04 18:20:15 +08:00
直接用 shell 就行,不要再用 php 把 shell 包起来!!!
|
32
tlday 2020-05-04 18:39:28 +08:00
我没有搞懂为什么要删掉,假如不需要删掉
你可以试试这个: head -10 access.log #读取前 10 行 head -20 access.log | tail -10 #读取 10-20 行 head -30 access.log | tail -10 #读取 20-30 行 ......依此类推 可能还有这个: mkfifo log_seeker cat access.log > log_seeker & exec 3< log_seeker head -10 log_seeker #读取前 10 个 head -10 log_seeker #读取下 10 个 head -10 log_seeker #读取下 10 个 ...依此类推 完了使用 fg # 调出上面的 cat 进程 Ctrl+C 掉 exec 3<&- # 关掉用来保持 cat 进程的 reader 进程,参考: https://unix.stackexchange.com/questions/366219/prevent-automatic-eofs-to-a-named-pipe-and-send-an-eof-when-i-want-it |
33
muzuiget 2020-05-04 18:42:49 +08:00
#25 果然是 X/Y 问题。
|
34
tlday 2020-05-04 18:42:58 +08:00
我上面的例子,如果你不手动杀掉 cat 进程,或者关掉用来保持 cat 进程的 reader 进程,就可以“无论间隔多久,下一次程序运行也是读取接下来的十行”
|
35
tlday 2020-05-04 19:06:20 +08:00
不想文件越来越大是典型的 log rotation 的应用场景,你这是两个需求。
|
36
msg7086 2020-05-04 19:20:37 +08:00
你 sed 途中遇上 nginx 写入的话你就等着丢数据吧。
(丢的概率有多大呢?这么说吧,流量高的站百分百丢数据。) 好好的 logrotate 不用,偏要走邪道…… |
37
mostkia 2020-05-04 20:09:54 +08:00
php 相关的程序日志,可以存到 SQLite 里面啊,一般 Nginx+PHP 的环境都带的。操作真的方便一个数量级,虽然都带文件锁,但你写 TXT 绝对好不到哪里去。以后导入导出也方便。如果你是要存 nginx 的日志的话,直接每天分割日志不就行了,然后可以视文件大小或者日期进行旧文件管理。
|
38
ClarkAbe 2020-05-04 20:17:24 +08:00 via iPhone
删这 10 行用乐观锁,其他的保持原样读写
|
39
lepig 2020-05-04 20:46:20 +08:00
这好像 PHP 面试的时候 经常会问 怎么使用 PHP 处理大日志文件 擦
|
40
dreamage 2020-05-04 21:17:59 +08:00
es 不香么
|
41
changePro 2020-05-04 21:41:26 +08:00 via Android
典型的错误案例,怎么解决都是错。
|
42
vk42 2020-05-04 22:23:49 +08:00
@frozenway 控制 log 文件大小不是 logrotate 的事,为啥要自己瞎搞? OS 的文件设计模型就是不适合从头部和中间删内容,不然 ftruncate 为啥不直接提供接口。如果你 log 文件本身上 G,你的这个解决方案真的是嫌 server 闲得没事干……
|
43
hallDrawnel 2020-05-04 22:27:45 +08:00
典型的 XY Problem 例子,还好第一个回帖的就把方向带回来了。
|
44
tozp 2020-05-04 22:32:54 +08:00
你实现了也不可取,实时操作 IO 占用太多资源,不如全放内存,周期性再写入文件。
|
45
xuanbg 2020-05-04 23:09:17 +08:00
日志的打开方式只有两种。一种是结构化后进行各种指标统计,你可以想象为一个监控大屏。另一种是用一个或若干个关键词搜索出相关的日志,你可以想象为系统出了问题通过日志排查错误。
楼主你这种日志的打开方式说不好听点纯粹是没事干…… |
46
sparkmlib 2020-05-04 23:40:39 +08:00
logstash + ES + kinba
|
48
CoderGeek 2020-05-05 10:03:28 +08:00
可以将文件分段存储 1 天一个分为大小或后缀的多个文件 nginx 也可以设置 再用 shell 直接读取都可以的 你这个删除在写入的思路不太合适
|
49
fensou 2020-05-05 11:45:09 +08:00 via iPhone
@sparkmlib logstash 换 filebeat+nginx module,连 dash 都自带了
|
50
fensou 2020-05-05 11:45:52 +08:00 via iPhone
graylog 其实更方便
|