某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分)にした場合にどの程度軽減できるか等確認が必要と思います。