CubicLouve

Spring_MTの技術ブログ

ログについてのまとめ

ログとは

時系列順になっているデータのこと。

全てが過去に発生する。

データログ - Wikipedia

ログ取得の目的

  • 記録・履歴(点)
    • 事象単体が意味を持つ場合に、時刻を含めてそのときの状況のデータを記録する
      • エラーログ
      • クラッシュログ
  • 変化量を捉える(線)
    • 時系列順に連続して観察したい場合に、時刻を含めてその時の状況のデータを記録し、その後に連続性を確認する
    • 連続性を確認するために、グラフなどで可視化する必要がある場合が多い

ログの設計

ログは出そうと思えばいくらでもだせる。

(それこそメソッド呼び出し単位で)

全部を出すと必要なデータが埋もれてしまう。

なので、ログの目的を明確化し、必要なログだけを出すようにする。

name Who 誰が Whom 誰に対して Where どこに 最終的な出力場所 What 何を When いつ 出力するタイミング Why なぜ HOW to どのように 出力方法 How many どれくらいの量 How much コスト感
アクセスログ Web サーバー 開発者 Hadoop アクセスログ アクセスするたびに ユーザー調査のため fluentd 100 logs / sec
アプリログ
分析ログ

ログの内容

ログの内容の基本的なもの。

情報は出力しすぎるとコストになるので出力する情報が必要か検討する。

名前 説明 詳細
When いつ 出力日時 yyyy-MM-ddTHH:mm:ss.ffffff、単位、出力時刻のタイムゾーン等を決めておく
Where どこで 出力された場所 アプリ名 ホスト、サーバーのIPアドレス プロセスID ログを出力したコードのパスや行数
Who 誰が クライアントのIPアドレス、ユーザーID、ユーザーエージェント、MySQLIPアドレス
What 何を ログレベル メッセージ 理由とか 実行コマンド

ログレベル

多くのアプリケーションで、アプリケーションの状態や処理内容を開発者に通知するためのログに重要度(ログレベル)を設定する。

(分析用のログにはないこともある)

ここでは代表的なログレベルについて記載する。

ログレベル 概要 説明 出力先 運用時の対応
fatal 致命的なエラー コンソール, ファイル 即時対応が必要
error エラー コンソール, ファイル 営業時間内のみ対応
warn 警告 コンソール, ファイル 次回リリースまでに対応
info 情報 コンソール, ファイル 対応不要
debug デバッグ情報 ファイル 出力しない

設定されたログレベルによって、ログの出力をコントロールできるようにしておく。(開発環境ではdebugまで出力するが、本番環境ではinfoまでしか出力しないようにするとか)

ログのフォーマット

ログの管理

ローテーションと保存期間

一つのファイルにログを書き続けると、一ファイルあたりの容量が増えていくのであとで加工しにくい(ログの肥大化)。

一定の容量や期間でログをまとめて別ファイルにして管理するようにする。

また一定期間を過ぎたログを削除もしくバックアップサーバー等に転送することで、サーバーのディスク容量があふれるのを防ぐ

logrotateなどがその役割を担ってくれている。

ログの活用

流量の監視

ログの送信方法

大量に送る場合の負荷

参照

dev.classmethod.jp

techblog.yahoo.co.jp

8.2.1 ログの運用

www.ipa.go.jp

Ruby2.4に上げたら"ArgumentError: key must be %d bytes" のエラーが出るようになったことの調査と暗号化の復習

Rubyの2.4以上から、共通鍵暗号を扱うOpenSSL::Cipherにおいて、暗号化鍵と初期化ベクトル(IV)を設定する際に、指定した暗号化方式の鍵長のビット数を超えて指定した場合、ArgumentErrorを返すようになりました。

irb(main):001:0> require 'openssl'
=> true
irb(main):002:0> c = OpenSSL::Cipher.new('aes-256-cbc')
=> #<OpenSSL::Cipher:0x007fc3c389da30>
irb(main):003:0> c.encrypt
=> #<OpenSSL::Cipher:0x007fc3c389da30>
irb(main):004:0> c.key = "1" * 33
ArgumentError: key must be 32 bytes
    from (irb):4:in `key='
    from (irb):4
    from /Users/hoge/.rbenv/versions/2.4.1/bin/irb:11:in `<main>'
irb(main):018:0> c.iv = "1" * 17
ArgumentError: iv must be 16 bytes
    from (irb):18:in `iv='
    from (irb):18
    from /Users/hoge/.rbenv/versions/2.4.1/bin/irb:11:in `<main>'

2.3までは短い場合のみエラーになっており、長い場合は切り捨てて使っていました。

https://github.com/ruby/ruby/blob/v2_4_0/doc/ChangeLog-2.4.0#L4332

github.com

class OpenSSL::Cipher (Ruby 2.4.0)

切り捨ててしまうのは、そもそもOpenSSLの仕様です。

なぜ切り捨てるようにできるのか?というのを暗号化の復習も兼ねて調べてみました。

暗号化

暗号化とは、意味の分かる情報(平文)を、意味の分からない情報(暗号文)に変換することを言います。

また、意味の分からない情報を意味の分かる情報に戻すことを復号(化)と言います。

暗号 - Wikipedia

暗号化する際に使う変換のアルゴリズムとかの歴史を追っていくと終わらないので、こちらを是非読んで貰えれば。

暗号化周りをわかりやすく読みやすく書いている本なので一読することをおすすめします。

AESとは

今回は暗号化方式の一つのAESを取り上げます。 AESはブロック暗号という暗号アルゴリズムに当たります。

ブロック暗号は、特定の固定長のビット数のまとまり(ブロック)に分けて、ブロックごとに暗号化していく暗号アルゴリズムのことです。

ブロックのビット数はブロック長と呼ばれます。

AESは128ビット(16バイト)のブロック長のみです。

暗号化する対象は、この固定長のまとまりであるブロック一つより大きいことがほとんどなので、 ブロック長ごとにブロック暗号アルゴリズムを繰り返し使って全体を暗号化する事になります。

この繰り返しの方法をブロック暗号のモードと呼びます。(複数の方法があります)

また、AESは暗号化と復号に同一の(共通の)鍵を使う対称鍵暗号化方式(共通鍵暗号方式)です。

AESの暗号化について

AESでは暗号化の鍵のビット長(鍵長)は128ビット、192ビット、256ビットが選択可能です。

この鍵を使って、ブロック長の128ビットと同じ長さのサブ鍵を作成して、それを利用して暗号化を行います。

なので、ブロック長と同じ長さである必要はありません。

鍵長がながければ長いほど、暗号強度は上がります。

AESの暗号化・復号ロジックの詳細は

の3章や

www.atmarkit.co.jp

などを参照ください。

ブロック暗号のモード CBC(Cipher Block Chaining)について

一つ前の暗号ブロックと平文ブロックのXOR(排他的論理和)を取ってから暗号化を行うモードです。

初期化ベクトル(IV)

最初の平文を暗号化するときには一つ前のの暗号化ブロックがないので、1ブロック分のビット列を用意する必要があります。 このビット列を初期化ベクトル(IV)といいます。

CBCモードの暗号化、復号化のフロー

CBCモードのフローは下記の通りです。

CFB encryption 作者 Gwenda (PNG version), WhiteTimberwolf (SVG version) (PNG version) [Public domain], ウィキメディア・コモンズ経由で

CFB decryption

暗号利用モード - Wikipedia

長い鍵と初期化ベクトル(IV)は切り捨てても問題ない?

そもそもAESの場合だと、鍵長を長くしても扱えませんし、IVを長くしてもブロック長を超えて与えても使えないから切り捨てるしかないですね。

でも、意図せずそういう設定にしてしまった可能性があるので、Rubyではあえてエラーにしているということかなと思います。

鍵のとIVを生成

ビット列として十分のランダムであることが求められます。

例えば鍵長が128ビットだと、2の128乗で340282366920938463463374607431768211456通り組み合わせがあります。

ただし、a-z A-Z 0-9 のasciiだけ鍵を作ろうとすると、62 の 16乗(1byte = 8bit)で、47672401706823533450263330816通りの組み合わせに減ってしまいます。

そこで、Rubyであれば、 module SecureRandom (Ruby 2.4.0) を使って、安全な鍵を生成するのがよいかと思います。

irb(main):001:0> require 'securerandom'
=> true
irb(main):002:0> SecureRandom.base64(16)
=> "NkIG8GcEL9fYTH+BXKYjQg=="

参考

理解してるつもりの SSL/TLS でも、もっと理解したら面白かった話 · けんごのお屋敷

thinkit.co.jp

The AES-CBC Cipher Algorithm and Its Use with IPsec

http://www.risk.tsukuba.ac.jp/pdf/group-work2005/2005group-4-resume.pdf

鍵 (暗号) - Wikipedia

openssl/evp_enc.c at 64846096b18340b9a39ddd29a7a0e23c56f22959 · openssl/openssl · GitHub

この記事は、クリエイティブ・コモンズ・表示・継承ライセンス3.0のもとで公表されたウィキペディアの項目「暗号利用モード」を素材として二次利用しています。

壊れたgzipを調べたときのメモ

壊れたgzipがあり、展開できないと言われて調査したときにどうやったかのメモ

gzipとは

www.gzip.org

www.futomi.com

zcatで展開できるところまでしてみる

zcatは破損した位置までのデータを修復できる。

展開できたデータの最後を確認して修復する。

バイナリを見る

壊れているgzipの内容

$ od -xc data.json.gz | tail
        342 213 322 264   @ 370   D 024 365 221 243 003   )   u   3   >
2572260    346a    d38e    1aea    bcb8    7f2f    5a69    d8f8    0865
          j   4 216 323 352 032 270 274   / 177   i   Z 370 330   e  \b
2572300    0f84    f0a9    9d00    f404    03af    33e1    f451    e212
        204 017 251 360  \0 235 004 364 257 003 341   3   Q 364 022 342
2572320    e79b    818a    b9f8    6228    36a0    91d9    7edb    173c
        233 347 212 201 370 271   (   b 240   6 331 221 333   ~   < 027
2572340    20d0    f29c    ac0f    732d    b57b    4cb7    0a01
        320     234 362 017 254   -   s   { 265 267   L 001  \n
2572356

最後に改行文字が入っていた。

gzipを書き出すときに Kernel.#puts module function Kernel.#puts (Ruby 2.4.0) とかを使うと起きそう。

直してみる

Vim 上で :%!xxdをして、hexdumpする

:%!xxd -r でバイナリで書き戻して完了

$ od -xc data_zcat_json.gz | tail
        213 322 264   @ 370   D 024 365 221 243 003   )   u   3   >   j
2572300    8e34    ead3    b81a    2fbc    697f    f85a    65d8    8408
          4 216 323 352 032 270 274   / 177   i   Z 370 330   e  \b 204
2572320    a90f    00f0    049d    aff4    e103    5133    12f4    9be2
        017 251 360  \0 235 004 364 257 003 341   3   Q 364 022 342 233
2572340    8ae7    f881    28b9    a062    d936    db91    3c7e    d017
        347 212 201 370 271   (   b 240   6 331 221 333   ~   < 027 320
2572360    9c20    0ff2    2dac    7b73    b7b5    014c
            234 362 017 254   -   s   { 265 267   L 001
2572374

参照

技術/歴史/zip,gzip,zlib,bzip2 - Glamenv-Septzen.net

http://www.gzip.org/algorithm.txt

Man page of GZIP

qiita.com

CloudWatch Alarms の Treats Missing Dataの意味

よくわからかなかったので整理

docs.aws.amazon.com

configure(コンソール) configure(api) 意味 英文
Missing missing 過去に遡ってデータを見に行く the alarm looks back farther in time to find additional data points
Good notBreaching 欠落データポイントで、しきい値内であることを示す(アラート収まる) treated as a data point that is within the threshold
Bad breaching 欠落データポイントで、しきい値を超えていることを示す(アラート飛ぶ) treated as a data point that is breaching the threshold
Ignored ignore 欠落データポイントでアラーム状態の変更がトリガーされない the current alarm state is maintained

特定のJSONの圧縮効率を調べてみる(snappy、gzip、xz、lz4、zstd)

snappyが入っているのは察してほしい

データの詳細は後で書く。(これも察して欲しい。だいぶ偏ったデータではある)

これから詳細をちゃんと書くが、一旦ここにおく

マシンスペック

iMac使っています。

% system_profiler SPHardwareDataType
Hardware:

    Hardware Overview:

      Model Name: iMac
      Model Identifier: iMac14,2
      Processor Name: Intel Core i5
      Processor Speed: 3.2 GHz
      Number of Processors: 1
      Total Number of Cores: 4
      L2 Cache (per Core): 256 KB
      L3 Cache: 6 MB
      Memory: 8 GB
      Boot ROM Version: IM142.0118.B00

% sysctl machdep.cpu.brand_string
machdep.cpu.brand_string: Intel(R) Core(TM) i5-4570 CPU @ 3.20GHz

結果

圧縮方式 圧縮時間(秒) 伸長時間(秒) 圧縮後サイズ(KB)
なし 159320(156KB)
snappy 18913(18K)
gzip 9982(9.7K)
xz 7024(6.9K)
lz4 23095(23K)
zstd 9960(9.7K)

実行時間の結果

github.com

圧縮時

Warming up --------------------------------------
              snappy    22.000  i/100ms
                gzip    20.000  i/100ms
                  xz     2.000  i/100ms
                 lz4    24.000  i/100ms
                zstd    21.000  i/100ms
Calculating -------------------------------------
              snappy    802.750  (±115.7%) i/s -      1.254k in   5.373229s
                gzip    295.138  (±40.7%) i/s -    980.000  in   5.055020s
                  xz     22.329  (± 4.5%) i/s -    112.000  in   5.030328s
                 lz4    949.545  (±110.1%) i/s -      1.224k in   5.053683s
                zstd    892.079  (±117.1%) i/s -      1.302k in   5.069196s

伸長時

Warming up --------------------------------------
              snappy   851.000  i/100ms
                gzip   414.000  i/100ms
                  xz   111.000  i/100ms
                 lz4   861.000  i/100ms
                zstd   577.000  i/100ms
Calculating -------------------------------------
              snappy     10.356k (±16.0%) i/s -     51.060k in   5.081812s
                gzip      4.655k (±10.2%) i/s -     23.184k in   5.039399s
                  xz      1.188k (± 7.7%) i/s -      5.994k in   5.080418s
                 lz4     10.312k (±12.0%) i/s -     50.799k in   5.000477s
                zstd      6.597k (± 8.4%) i/s -     32.889k in   5.023823s

デーモンとは

メモ書き程度に

デーモン

語源は悪魔のデーモンではなく、守護神のほうらしい。 デーモン (ソフトウェア) - Wikipedia

まあ、それはそれとして デーモン(daemon)は長時間動き続けるプロセスのことです。 APUEのデーモンより

  • ファイルモード作成時マスクをumask 0でリセットする

    • プロセスがファイルを作成するとき、マスクが許可をオフにすることを避けるため
  • 新しいセッションを作成する( 制御端末から切り離し、プロセスグループのリーダとなり、セッションのリーダーとなる)

    • forkして、親をexitする
    • setsidを呼ぶ
    • 制御端末がないので、出力の表示場所がない
      • ps のTTYが ? or ?? になっている
    • エラー状態の報告はsyslogを使う等する
  • cwdをルートディレクトリ(/)に変更する

  • 不必要なファイルディスクリプタをcloseしておく

  • 標準入力、標準出力、標準エラー出力を閉じる

    • 対話的なインターフェースから入力も受けない
    • 同じ端末装置に他のユーザーがログインしても、デーモンの出力が端末に現れないようにする

rubyだとProcess.daemonを呼ぶだけでデーモンになる

Refernce