SQLOGS

8403 ワード

OpenMarket - 2021年6月3日
パーカーDeWildeによって
私はログが大好き!
Easy to add
Logger configurable to give you useful information for free: time, server, class, request id, etc.
Simple, easy to understand
For the dev team’s eyes, changes are low impact
Fantastic tool for debugging, troubleshooting, and general visibility
も、ログよりも、そこには、素晴らしいですログの周りのツールです!私の経験はエルク(エラスティックサーチ、Logstash、Kibana)でありますが、Splunk、Grayylog、および他の多くのような他の同様の驚くべきツールがあります.ちょうど曇りません.
ヘラジカは私の本でかなり魔法です.これは、ログの巨大なボリュームを読み込み、ほぼ瞬時にそれらを検索することができます、分割秒で結果の膨大な量を返します.それは複数のフィールドにログを分割することができますし、それらに基づいてフィルタログ.その全文検索かなりきれいに(あなたは全体のトークンを検索している限り)、とKibanaのUIは非常に直感的です.私も、それはさらに強力にすることができますJSONのログを使用しないでください!
マジックログツールを越えて、まだ答えがないという質問がたくさんあります.
Find all duplicate log lines
    If there are duplicate log lines, find out which request IDs are duplicate
    Find out how many distinct log lines were duplicated, and how many times each was duplicated, and return the 10 most duplicated along with count
Find all request IDs that went through step A but not step B
Find all requests that took more than 50ms*
Find the first and last log lines related to every user
これはJSONログで可能であるかもしれません、私はプレーンテキストログを使用するだけです、そして、私はそれが可能であると思いません
ほとんどのログラインでは、答えを見つけるために、または範囲のクエリのようなものだけをテキストインデックスを持っている必要がありますほとんど何も.
構造化されたデータをとるのが得意だったツールがあれば、複数のレコードを結合したり、範囲の問い合わせをしたり、データを柔軟にグループ化したりするようなことをしていました.
SQL!私はほとんどのログと同じくらい大好き!47年後、それはまだ構造化データを照会する驚くほどアクセス可能で汎用的な方法です.より洗練されたデータモデルと問い合わせ言語があるかもしれません、そして、それはすべての自身の長所と短所を持ちます、しかし、SQLとして広く使用されて、普遍的に理解されています.
それで、私がSQLが好きであるならば、そして、私はログが好きです、なぜ、私は私のログをSQLできませんか?愚かな質問は、もちろん、あなたのログをSQLすることができます!おそらくバグの解決策をサポートするいくつかの特定のログ管理ソリューションを見つけたり、SQL構文をサポートしているいくつかのDBにJSONログをエクスポートすることができます.しかし、もしあなたが私のような場合、必要とされている必要があります.
まず最初に行う必要があるのは、ログをリレーショナルフォームに変換することです.あなたがJSONを使用している場合、それはおそらくかなり簡単です、ちょうどJSONをインポート、あなたが望むフィールドを選択し、離れて行く.あなたが私のようで、平文のログを使うならば、あなたはもう少し手動作業をする必要があります、しかし、リレーショナルフォームへの転換は一般にかなり簡単です.
私のお気に入りの方法はPythonです.私が本当に気が変であるとき、私はパイソンクライアントを使用しているFererticsearchから直接ログをつかみます.他の回では、単にログファイルを直接読むのは簡単かもしれません.
例のために、彼らのログインセッションがリセットされて、問題について顧客から不満があったと仮定しましょう.あなたは何が起こっているだけでなく、問題の範囲に良い把握を得ることを考え出すことを帯びている.
最初の場所は、問題をユーザーに分離することです.彼らのセッションがリセットされているならば、我々は小さなウインドウの中で複数回ログインしている同じユーザーを見たいと思っています.残念ながら、ここで私たちを助けることができる単一のログラインはありませんが、我々の友人のSQLは、救助に来ることができます!
以下のようなログファイルがあるとしましょう.
021-05-28T09:11:11,501 INFO pool-1-thread-6 IdentityServiceClient 000-X6HAJ-U32KP-6PD6C-4HIUJ-LGN - User banner with account id 94404 successfully logged in
2021-05-28T09:13:03,469 INFO pool-0-thread-9 IdentityServiceClient 000-R992R-4KV1C-BEE3Y-FIGRD-GST - User spock with account id 16059 earned a gold star!
2021-05-28T09:14:15,727 INFO pool-2-thread-15 SandPounder 000-DZSXL-MT6K8-Y574Z-HLYOO-SPD - Pounded 5 pounds of sand.
各ログ行には同じ要素があります.
Timestamp
Log Level
Thread
Class/Function
Request Id
Payload/message
あなたはこれらの部分にログラインを分割し、一日を呼び出すことができますが、それはログインのためのユーザーのようなものに基づいてクエリをするのは難しいようになります.私は通常、私は私が気にかける線を得るために私のログを前処理するのが好きです.これはPythonで行うことができますが、必要に応じてログを引くだけでgrepを簡単にすることができます.
grep "IdentityServiceClient" example.log | grep "successfully logged in" > example_filtered.log
私が気にかける線があるだけで、私は彼らがすべて同じフォーマットであるということを知っています.
from datetime import datetime, timezone
# open our file and iterate through the lines
line_dicts = []
with open("example_filtered.log", 'r') as log_file:
   for line in log_file:
       parts = line.split(' ') # space delimited for first fields
       time_string = parts[0]
       log_level = parts[1] # we already filtered so same for every line
       thread = parts[2] # not relevant to our investigation
       function = parts[3] # we already filtered so same for every line
       request_id = parts[4]
       # useful to have numeric form of time for doing math in sql
       epoch_millis = int(
           datetime.strptime(time_string, "%Y-%m-%dT%H:%M:%S,%f")
           .replace(tzinfo=timezone.utc)
           .timestamp() * 1000)
       # notice " - " before every payload. Split on first instance since
       #  string will not appear before the payload, but may appear inside
       payload = line.split(' - ', 1)[1]
       # system does not allow spaces in username/id,
       #  so let's just tokenize same way
       payload_parts = payload.split(' ')
       username = payload_parts[1]
       user_id = payload_parts[5]
       # lets keep the parts we care about in a dictionary
       line_dict = {
           "timestamp": time_string, "epochMillis": epoch_millis,
           "requestId": request_id, "username": username, "userId": user_id
       }
       line_dicts.append(line_dict)
SQLデータベースを設定する必要があります.私は通常、Sqliteを使用して、その超簡単にセットアップすると、私はログで行うほとんどのことに十分な強力な.さらに、あなたはすべてのPythonの中からそれを行うことができます!
# continuing on from above file
import sqlite3
import os
DBNAME = 'techblog.db'
# Remove old DB if exists
try:
   os.remove(DBNAME)
except OSError:
   pass
# connect to the DB
with sqlite3.connect(DBNAME) as conn:
   # Get a cursor, which is required to use the connection
   c = conn.cursor()
   # setup the schema
   c.execute('''
   CREATE TABLE logins (
   timestamp TEXT,
   epochMillis INTEGER,
   requestId TEXT,
   username TEXT,
   userId TEXT)
   ''')
   # add the data - takes a string with ?'s and an iterable to fill in the ?'s
   for cur_line in line_dicts:
       c.execute('''
       INSERT INTO logins VALUES(?, ?, ?, ?, ?)
       ''', (cur_line['timestamp'], cur_line['epochMillis'],
             cur_line['requestId'], cur_line['username'], cur_line['userId']))
   # run the optimize command to ensure efficient queries in the future
   # this is sqlite specific -- for some reason it doesn't keep statistics
   # for the optimizer unless you tell it to
   c.execute('PRAGMA analysis_limit=400')
   c.execute('PRAGMA optimize')
   # commit, connection will close automagically due to using "with" to open
   conn.commit()
今、我々はSQLデータベースを持っており、我々の調査を行う準備が整いました!私は通常、任意のSQLite互換クライアントが動作しますが、私のデータベースを見てDBeaverと呼ばれるツールを使用します.また、Pythonから直接DBを照会することもできます(しかし、私は、何かを自動化するならば、私はそれをするだけです、それは目的で作られたデータベースクライアントより人間工学的でありません).
DBeaverのSQLiteに接続することは簡単です.新しいデータベース接続-> sqlite -> next -> path作成したファイル(私の場合はtechblog . db )-> finishを設定する

データベース内のデータを見ることができます.私はこのデータを使用する方法の1つの例を示しますが、SQLを知っている限り、世界はあなたの牡蠣です!
我々のセッションを持つユーザーとの問題を抱えていた思い出し、再度ログインする必要があります.我々は、これが問題の範囲と同様に複数のユーザーに影響を及ぼしているかどうか見たかったです.SQLスクリプトを少し書きました.
SELECT a.username, COUNT(*) as 'number of repeated logins within a minute'
FROM logins a, logins b -- simple full join
WHERE a.requestId  != b.requestId  -- don't want to match self
AND a.userId  == b.userId  -- same user logging in
AND a.epochMillis < b.epochMillis -- let’s ensure a is always before b
AND (b.epochMillis - a.epochMillis) < 60000 -- let’s only look at logins less than a minute apart
GROUP BY a.username -- get stats by user
ORDER BY COUNT(*) DESC -- highest counts first
こうすると以下のように出力されます:

我々は7つのユーザーだけを与えられ、これはかなり大きな問題のように思える!より良い解決策を探し始める!多分、我々のデータベースのそれらの要求IDは、我々を助けることができました.
SELECT COUNT ( DISTINCT username ) AS "total users in system"
FROM logins
私はあなたがあなたのツールボックスの別のツールとしてこれを維持することを願っています.それは設定するのに少し時間がかかりますが、時々あなたにキバナのようなツールで簡単ではない何かを与えることができます.同僚はまた、SQLテキストとしてよくフォーマットされたテキストファイルを照会することができるデータとしてQ -テキストなどのいくつかの他のクールなツールを私に示している.これは私が頻繁に使用する何かではない、1年に1回か2回かもしれないが、私はそれを必要とするとき、私は私の自由にこのテクニックを持っていることがうれしい.
私の例のログとコードは、あなたの便宜のためにGISTとして利用できます