Edited at

Datadog ログ監視でログ本文を通知

More than 3 years have passed since last update.

某abbix等だとログ本文を一覧で表示できたりしますが、

Datadogでは解析した物を使用する前提のようで、

本文を送る機能は用意されていません。

syslog(/var/log/messages)を対象に、

Datadogで任意の文字列に合致したログ本文を通知する設定を行いました。


事前準備


環境

CentOS 6.7


DatadogAgent インストール

Datadogのメニューから辿ると、各OS(distribution)用のインストールコマンドが用意されていますので、そちらに沿って対象サーバにインストールします。


  • [Integrations] -> [Agent] -> [CentOS/RedHat]



pyparsing インストール

ログをパースするのに必要になるのでpipでインストールします。


注意点としてDatadogAgentは独自でpythonを持っており、

OSにインストールされているpythonに対してインストールしてもDatadogAgent内の処理では使用されません。

尚、pipは古いバージョンだったのでアップグレードしました。

/opt/datadog-agent/embedded/bin/pip install -U pip pyparsing

# /opt/datadog-agent/embedded/bin/pip --version
pip 8.0.2 from /opt/datadog-agent/embedded/lib/python2.7/site-packages (python 2.7)


標準でインストールされていた python 2.6

/usr/bin/python 用のpipでインストールしてもDatadogAgent(collector)からは使用できません。

# which python

/usr/bin/python
# python --version
Python 2.6.6
# which pip
/usr/bin/pip
# pip --version
pip 8.0.2 from /usr/lib/python2.6/site-packages (python 2.6)


DatadogAgent(collector)用の Python 2.7

daemonの設定ファイルを見ると、ログ解析を行うcollectorが使用するpythonのパスが記載されています。

同ディレクトリにpipも存在するので、こちらを使用します。

# cat /etc/dd-agent/supervisor.conf

・・・略・・・
[program:collector]
command=/opt/datadog-agent/embedded/bin/python /opt/datadog-agent/agent/agent.py foreground --use-local-forwarder
・・・略・・・
# /opt/datadog-agent/embedded/bin/python --version
Python 2.7.10
# /opt/datadog-agent/embedded/bin/pip --version
/opt/datadog-agent/embedded/bin/pip --version
pip 6.1.1 from /opt/datadog-agent/embedded/lib/python2.7/site-packages/pip-6.1.1-py2.7.egg (python 2.7)


対象ファイルのパーミッション

今回の監視対象ログはsyslogであるため、root以外に権限がありません。

監視するためには読込権限が必要になるため、dd-agentユーザに付与します。(dd-agentをrootグループに所属させ、ファイルにはグループの読込権限のみ付与しています。)

# usermod -g dd-agent -G root dd-agent

# chmod 640 /var/log/messages
# usermod -g dd-agent -G root dd-agent
# chmod 640 /var/log/messages
# logrotate設定にも追加
# vi /etc/logrotate.d/syslog
・・・略・・・
create 0640 root root
・・・略・・・


カスタムログパーサ

CentOSのsyslog(messages)を例にパーサを作成します。

公式ドキュメントと先輩様のスクリプトの参考(拝借)です。


  • syslog-parser.py

from pyparsing import Word, alphas, Suppress, Combine, nums, string, Optional, Regex

from time import strftime
import os.path
import time

def payload_event(line, log_array, alert_type):
payload = {}
payload["alert_type"] = alert_type
payload["event_type"] = "syslog.error"
payload["aggregation_key"] = log_array[3]
payload["host"] = log_array[3]
payload["msg_title"] = log_array[4]
payload["msg_text"] = os.path.basename(__file__) + ' : ' + line
return payload

def syslog_parser(log, line):
# ignore case (specified in lower case)
if ' error ' in line.lower():
alert_type = 'error'
elif ' warning ' in line.lower():
alert_type = 'warning'
else:
return
# case sensitive
#if ' error ' in line:
# alert_type = 'error'
#elif ' warning ' in line:
# alert_type = 'warning'
#else:
# return

ints = Word(nums)
month = Word(string.uppercase, string.lowercase, exact=3)
day = ints
hour = Combine(ints + ":" + ints + ":" + ints)
timestamp = month + day + hour
hostname = Word(alphas + nums + "_" + "-" + ".")
appname = Word(alphas + "/" + "-" + "_" + ".") + Optional(Suppress("[") + ints + Suppress("]")) + Suppress(":")
message = Regex(".*")

pattern = timestamp + hostname + appname + message
parsed = pattern.parseString(line)
event = payload_event(line, parsed, alert_type)
return [event]

def test():
# Set up the test logger
import sys
import logging
logging.basicConfig(level=logging.DEBUG)

param = sys.argv
if (len(param) != 2):
print 'Usage: python %s "TestMessage"' %param[0]
quit()

# Call the parse function
actual = syslog_parser(logging, param[1])

# Validate the results
print 'Input:'
print param[1]
print 'Output:'
print actual

if __name__ == '__main__':
# For local testing, callable as "python /path/to/syslog-parser.py"
test()


各関数説明


payload_event

ログ本文からDatadogのイベントフィールドを生成します。


この例では message_text はログ全文と検索用にスクリプト名を設定しています。


syslog_parser

先頭のif文で error|warning の振り分けを行います。


マッチしない行に対しては何も処理しません。(ログ全行を送るのは避けています。)


test

テスト関数です。コマンドラインからのテストを実行します。


引数でログメッセージを渡す事で、渡した文字列とパース後の文字列を出力します。


テスト実行例

# python parser.py "テスト文字列"

/opt/datadog-agent/embedded/bin/python /opt/datadog-agent/agent/checks/libs/syslog-parser.py "`date +'%b %d %H:%M:%S'` `uname -n` dd.collector[9999]: WARNING (disk.py:74): Using \`use_mount\` in datadog.conf has been deprecated in favor of \`use_mount\` in disk.yaml"
# 出力例
Input:
Feb 22 04:00:03 demo-clpami6 dd.collector[9999]: WARNING (disk.py:74): Using `use_mount` in datadog.conf has been deprecated in favor of `use_mount` in disk.yaml
Output:
[{'alert_type': 'warning', 'event_type': 'syslog.error', 'msg_title': 'dd.collector', 'host': 'demo-clpami6', 'msg_text': 'Feb 22 04:00:03 demo-clpami6 dd.collector[9999]: WARNING (disk.py:74): Using `use_mount` in datadog.conf has been deprecated in favor of `use_mount` in disk.yaml', 'aggregation_key': 'demo-clpami6'}]


格納場所と設定ファイル

datadog.conf に監視対象のログとパーススクリプトを指定します。

# vi /etc/dd-agent/datadog.conf

・・・略・・・
dogstreams: /var/log/messages:syslog-parser:syslog_parser
・・・略・・・

DatadogAgentの PYTHONPATH 配下であればパスの記述を省略できます。


PYTHONPATH はdaemonの設定ファイルに記載されています。(ここでもcollectorが対象です)

# cat /etc/dd-agent/supervisor.conf

・・・略・・・
[program:collector]
・・・略・・・
environment=PYTHONPATH='/opt/datadog-agent/agent:/opt/datadog-agent/agent/checks/libs:$PYTHONPATH'
・・・略・・・

今回は PYTHONPATH であるlibs配下に格納しています。

/opt/datadog-agent/agent/checks/libs/syslog-parser.py


有効化と確認

スクリプトの配置、設定ファイルへの追加、読込権限付与等、

準備が整った所でDatadogAgentを再起動して反映します。

# service datadog-agent restart

Stopping Datadog Agent (using killproc on supervisord): [ OK ]
Starting Datadog Agent (using supervisord): [ OK ]

/var/log/datadog/collector.log に以下のようなログが出力されていれば成功です。

yyyy-mm-dd hh:mm:dd JST | INFO | dd.collector | checks.collector(datadog.py:151) | dogstream: parsing /var/log/messages with <function syslog_parser at 0xXXXXXXXXXX> (requested syslog-parser:syslog_parser)


Datadog上での確認


参照

[Events] で参照できます。


通知設定

[Monitors] -> [New Monitor] から通知設定を行います。


今回はSlackのチャンネルへ通知します。


通知テスト

適当にログ出力を行い、Monitor設定で正しく通知されるかを確認します。

# logger -t TEST "`date +'%b %d %H:%M:%S'` `uname -n` dd.collector[9999]: warning LogParseTest"

通知メッセージにログ本文が含まれています。


今後の課題

試行回数が少ないのですが、連続して出力があった場合に通知が飛ばない事があるようです。

Monitorの設定で最短(1分)にした場合にどの程度軽減できるか等確認が必要と思います。