togatttiのエンジニアメモ

過度な期待はしないでください.

ファイルの各行にUUIDを付加するスニペット

ログ収集ツールのfluentdのuuid_keyを使う場合、ログにUUIDを振る必要がある。

こんなときシェルスクリプトで、whileやfor、uuidgenを組み合わせて、追記していたが、 行が膨大な場合、処理の遅延が気になったので、C言語で処理するプログラムを書いた。

プログラム

Ubuntu環境で、動かした。

依存ライブラリをインストールする。

$ sudo apt install uuid-dev

Cのプログラムは、こんな感じ。

#include <stdio.h>
#include <string.h>
#include <uuid/uuid.h>

int main(int argc, char *argv[]) {
  FILE *source, *target;
  char line[256];
  uuid_t uuid;
  char uuid_str[37];
  int len;

  source = fopen(argv[1], "r");
  target = fopen(argv[2], "w");
  while(fgets(line, 256, source)) {
    len = strlen(line);
    if (line[len-1] == '\n') {
      line[len-1] = 0;
    }
    uuid_generate_time_safe(uuid);
    uuid_unparse_lower(uuid, uuid_str);
    fprintf(target, "%s %s\n", line, uuid_str);
  }
  fclose(source);
  fclose(target);
  return 0;
 }

コンパイルする。

$ gcc -o append_uuid append_uuid.c -luuid

ベンチマーク計測

比較用のファイルを用意する。

$ for i in `seq 10000`; do echo "abc" >> uuid_by_bash.txt; echo "abc" >> uuid_by_c.txt; done
$ wc -l uuid_by_bash.txt uuid_by_c.txt
10000 uuid_by_bash.txt
10000 uuid_by_c.txt
20000 total

まずは、Bashでやる場合(これがBashのベストプラクティスかどうかは知らない。。)

$ time cat uuid_by_bash.txt | while read line; do uuid=$(uuidgen); echo "$line $uuid" >> uuid_by_bash.txt.new; done

real    0m25.741s
user    0m1.268s
sys 0m7.632s
$ tail -1 uuid_by_bash.txt.new
abc 006b69fd-9ad0-4749-afe1-eef73c6ffad0

次は、Cで書いたプログラム。

$ time ./append_uuid uuid_by_c.txt uuid_by_c.txt.new
uuid_by_c.txt uuid_by_c.txt.new
real    0m0.020s
user    0m0.016s
sys 0m0.000s
$ tail -1 uuid_by_c.txt.new
abc d05dc0b5-bad5-11e6-81bd-000c291c1598

クソ速い。