loggerコマンドの1024バイト出力制限を回避する

logger コマンドの1024バイト制限

$ cmd | logger というように、コマンドの出力結果を logger コマンド経由で syslog 出力することがある。
極稀に syslog のメッセージが途切れているという事象があり、調べてみると logger コマンドは 1024 バイトまでしか出力できないようにハードコードされているとわかる。

1024 バイト制限は “RFC 3164 : The BSD syslog Protocol” に起因していて

The total length of the packet MUST be 1024 bytes or less.
If the packet has been expanded beyond 1024 bytes, then the relay MUST truncate the packet to be 1024 bytes.
http://tools.ietf.org/html/rfc3164

といったことが書かれている。

実際にこの動作を確認してみる

] $ python -c 'print "a"*1020 + "1234"'  | logger

というメッセージに対して

Dec 20 20:18:25 host01 jsmith: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa123
Dec 20 20:18:25 host01 jsmith: 4

というように 1023 バイトでメッセージが分断されている

1024バイトを超えて syslog 出力する方法

logger コマンドはハードコードされているので諦め、あまり凝らずに 1024 バイトを超えて syslog 出力する方法についてメモ。

一つ目の mlogger は既存の logger のコードを拡張して 1024 バイト制限を取っ払っている。
もう一つの方法は、標準入力を syslog(3) に渡すだけの省エネで姑息(だけとこれで困らないよね?)な手段。

mlogger コマンド

mloggerlogger のフォーク。
UDP/TCP/Socket といった各プロトコルで logger の上限サイズをあげている。

コードは github に上がっているので、野良インストールする。

$ git clone https://github.com/nbrownus/mlogger.git
Cloning into 'mlogger'...
remote: Counting objects: 119, done.
remote: Total 119 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (119/119), 66.73 KiB | 103.00 KiB/s, done.
Resolving deltas: 100% (53/53), done.
Checking connectivity... done.
$ make
gcc -Wall -Wextra -O3 -o mlogger mlogger.c
$ ./mlogger --help

Usage:
mlogger [options] [message]

Options:
 -d, --udp              use UDP (TCP is default)
 -i, --id               log the process ID too
 -f, --file <file>      log the contents of this file
 -h, --help             display this help text and exit
 -n, --server <name>    write to this remote syslog server
 -P, --port <number>    use this UDP port
 -p, --priority <prio>  mark given message with this priority
 -s, --stderr           output message to standard error as well
 -t, --tag <tag>        mark every line with this tag
 -u, --socket <socket>  write to this Unix socket
 -I, --indent <ms>      Will consider intended lines continuation of the previous line, within the timeout
                        specified in milliseconds
 -V, --version          output version information and exit

This mlogger is configured to send messages up to 65536 bytes.

mlogger で出力してみる

$ python -c 'print "a"*1024 + "1234"' | ./mlogger   # message size > 1kb
$ python -c 'print "a"*1024*2 + "1234"' | ./mlogger # message size > 2kb

ローカルサーバの /var/log/syslogを確認

Dec 20 20:19:22 host01 -c: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1234
Dec 20 20:19:24 host01 -c: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1234

1024 バイトに引っかかることなく出力できている。

syslog(3)直接呼び出し版

標準入力を syslog(3) に渡すプログラムを好きな言語で書く

この方式だと UNIX domain socket の制限に引っかからないサイズ内であれば、メッセージ送信できる。

rsyslog の wiki ページに Perl/C 版があるのでまずはそれをコピペ

http://wiki.rsyslog.com/index.php/Working_Apache_and_Rsyslog_configuration

元の wiki は Apache のログをパイプで渡すことを前提にしていて identhttpd になっていたりするので、適宜修正する。

Perl version

#!/usr/bin/perl
# usage:
# $ cmd | pl-logger.pl
use Sys::Syslog qw (:DEFAULT setlogsock);

setlogsock('unix');

# open our log socket
openlog('httpd', 'pid', 'local6');

# log all our input
while (<STDIN>) {
  syslog('info', $_);
}

# close the log socket
closelog;

C version

# usage:
# $ cmd | c-logger
#include <stdio.h>
#define SYSLOG_NAMES
#include <syslog.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, const char *argv[])
{
  if (2 != argc)
  {
    fprintf(stderr, "Usage: stdin-syslogd priority\n");
    exit (1);
  }

  const char *priority_name = argv[1];
  int priority = -1;
  int i;

  for (i = 0; prioritynames[i].c_name; ++i)
  {
    if (! strcmp(prioritynames[i].c_name, priority_name))
    {
      priority = prioritynames[i].c_val;
      break;
    }
  }

  if (priority < 0)
  {
    fprintf(stderr, "stdin-syslogd: priority \"%s\" not recognized",
      priority_name);
    exit (1);
  }

  openlog("httpd", LOG_PID|LOG_NDELAY, LOG_LOCAL6);

  char buffer[8192];

  while (NULL != fgets(buffer, sizeof(buffer), stdin))
  {
    syslog(priority, "%s", buffer);
  }
  return 0;
}

Python version

ついでに Python にも移植。

#!/usr/bin/python
# usage:
# $ cmd | py-logger.py
import sys
import syslog

syslog.openlog("py-logger",
               logoption=syslog.LOG_PID|syslog.LOG_NDELAY,
               facility=syslog.LOG_LOCAL6)
for line in sys.stdin:
    syslog.syslog(syslog.LOG_INFO, line)

実際に動かしてみると

$ python -c 'print "a"*1024*2 + "1234"' | ./py-logger.py

というメッセージに対して

Dec 20 22:12:30 host01 py-logger[22320]: aaaaaaaa...[snip]...aaa1234

というように 1024 バイトを超えて出力できている。

Advertisements
Tagged with: , ,
Posted in linux

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archives
  • RT @__apf__: How to write a research paper: a guide for software engineers & practitioners. docs.google.com/presentation/d… /cc @inwyrd 4 months ago
  • RT @HayatoChiba: 昔、自然と対話しながら数学に打ち込んだら何かを悟れるのではと思いたち、専門書1つだけ持ってパワースポットで名高い奈良の山奥に1週間籠ったことがある。しかし泊まった民宿にドカベンが全巻揃っていたため、水島新司と対話しただけで1週間過ぎた。 それ… 4 months ago
  • RT @googlecloud: Ever wonder what underwater fiber optic internet cables look like? Look no further than this deep dive w/ @NatAndLo: https… 4 months ago
  • @ijin UTC+01:00 な時間帯で生活しています、、、 10 months ago
  • RT @mattcutts: Google's world-class Site Reliability Engineering team wrote a new book: amazon.com/Site-Reliabili… It's about managing produc… 1 year ago
%d bloggers like this: