データを失うことなくシステムログをより小さなファイルに分割する方法

データを失うことなくシステムログをより小さなファイルに分割する方法

syslogここでは、ファイルをより小さな塊に分割しようとしています。これを行うには、次のスクリプトを使用します。

#!/bin/bash
date=$(date +%Y%m%d_%H%M)
 
cp /path/to/sys.log /path/to/chuck/file.log
cat /dev/null > /path/to/sys.log

cp /path/to/chuck/file.log /path/to/chuck/file_"$date".log
cat /dev/null > /path/to/chuck/file.log

スクリプトは5分ごとに実行され、それをsyslogより小さなログに分割して追加の処理に使用します。問題は、元のファイルとチャンクファイル
にいくつかの履歴がありません。syslogこの問題を解決する方法はありますか?

ここでチャンクファイルは約2GBです。syslog成長しています。

答え1

警告する:これは小さな最大サイズとimfile入力モジュールがあったため、バージョン8.2002では完全には機能しませんでした。一部のデータはログファイルから失われますが、ドキュメントでは通常小さなバッファサイズはサポートされていないことを警告します。


rsyslogを使用すると、ログファイルが特定のサイズを超えると回転する組み込みメカニズムが提供されます。あなたはただ チャンネル、ファイル名、最大サイズ、サイズを超えた場合に実行するスクリプト名を指定します。それから 使用 ファイル名の代わりにフィルタのチャネル名です。

たとえば、ファイル/home/me/rotatescriptが作成された50Mibytesを超えるとスクリプトを実行するには、/var/log/mylog次の名前のチャンネルを作成しますmylogrotatechan

$outchannel mylogrotatechan,/var/log/mylog,52428800,/home/me/rotatescript

そして*.* /var/log/mylogに交換

*.* :omfile:$mylogrotatechan

文書化されていないRainerScript構文を使用する最新のソース(2023年1月)には、テストスクリプトもあります。

action(type="omfile" file="/var/log/mylog" rotation.sizeLimit="52428800"
       rotation.sizeLimitCommand="/home/me/rotatescript")

一般的なスクリプトは次のとおりです。

#!/bin/bash
mv /var/log/mylog /var/log/mylog.$(date +%Y%m%d.%H%M%S)

答え2

私はPerlを使用します。ファイル::尾この目的のために(私は監視する必要があるほとんどすべて、つまり連続テールログファイルに使用します)。

#!/usr/bin/perl

# File::Tail need to be installed from a distro package e.g. 'apt
# install libfile-tail-perl' on debian, ubuntu, mint etc or from
# CPAN https://metacpan.org/pod/File::Tail
# BTW, File::Tail has several useful options, run `man File::Tail`
# for details.
use File::Tail;

# These two need to be installed from a distro package e.g. 'apt
# install libtimedate-perl' on debian, ubuntu, mint etc or from
# CPAN https://metacpan.org/release/TimeDate
use Date::Parse;
use Date::Format;

# These two modules are included with perl
use File::Basename;
use Scalar::Util qw(openhandle);

use strict;

# $logfile is hard-coded here, but you can get it from the command line
# e.g. with something as simple as `my $logfile = shift` or use one of
# the command-line option processing modules like Getopt::Std or
# Getopt::Long
my $logfile = '/var/log/syslog';

# the output dir is hard-coded here to `chunk/` in the current dir.
# set it to whatever you want, or get it from the command line.
my $basename = './chunk/' . basename($logfile);

# open a handle to the log file.  File::Tail will automatically
# re-open the log file if it gets rotated and re-created.
my $logref=tie(*LOG,"File::Tail", (name => $logfile, tail => -1));

my ($d, $t, $t2, $outfile, $chunk);

while(<LOG>) {
  # Example of handling two different common rsyslog logfile date
  # formats.  Adjust the regex(es) to suit YOUR log file.
  if (/^([[:alpha:]]{3} \d+ \d\d:\d\d):/i) {
    # Jul 25 00:00:02 ....
    $d = $1;
  } elsif (/^(\d{4}[ T]\d\d:\d\d):/) {
    # 2023-07-25T00:00:01.737457+10:00 ....
    $d = $1;
  } else {
    die "Couldn't find a known date format in:\n$_";
  };
  $t = str2time($d);

  if ($t - $t2 >= 300) {
    close($chunk) if openhandle($chunk);
    # Alternatively, you could run your chunk processing
    # program from here:
    # (this is really basic & untested but it should work...but
    # there are better ways of handling child processes.)
    # if (openhandle($chunk)) {
    #   close($chunk);
    #
    #   $SIG{CHLD} = "IGNORE";
    #   fork;
    #   exec("myprogram", $outfile) or
    #     warn "Couldn't exec 'myprogram $outfile'\n";
    # };


    $t2 = $t;
    $d = time2str("%Y%m%d_%H%M", $t);
    $outfile = "${basename}_$d";

    # Ignore output files that already exist, so that we can
    # just re-run this script if it gets killed for some reason.
    if (! -e $outfile) {
      print "opening new output file $outfile\n";
      open($chunk, ">", $outfile) or
        die "couldn't open $outfile for write: $!\n";
    }
  };

  print $chunk $_ if openhandle($chunk);
}

たとえば、同じ名前で保存してsplit-log-5min.pl実行可能にしてからchmod +x split-log-5min.pl実行します。ログファイルが終了するまで(Ctrl-Cやなどkill)、または書き込み用に出力ファイルを開こうとしたときにエラーが発生するまで、ログファイルのデータを実行して処理し続けます。

/var/log/syslogの抜粋でこのコマンドを実行し、その結果、数分の./chunk5分のチャンクを含むディレクトリが作成されました。

$ ls chunk/
syslog_20230725_0000  syslog_20230725_0519  syslog_20230725_1037
syslog_20230725_0007  syslog_20230725_0525  syslog_20230725_1043
syslog_20230725_0013  syslog_20230725_0531  syslog_20230725_1049
syslog_20230725_0019  syslog_20230725_0537  syslog_20230725_1055
[...many more deleted]
syslog_20230725_0455  syslog_20230725_1013  syslog_20230725_1531
syslog_20230725_0501  syslog_20230725_1019  syslog_20230725_1537
syslog_20230725_0507  syslog_20230725_1025
syslog_20230725_0513  syslog_20230725_1031

ちなみに、5分単位で処理する内容によっては、その単位を別々のファイルにコピーしなくても、このスクリプトで処理できます。たとえば、ファイルに書き込むのではなく、各行を配列に追加してから5分ごとに配列を処理して消去します。

関連情報