読者です 読者をやめる 読者になる 読者になる

ログをわかりやすく表示

SQL

DBに格納するログがあまりにも役に立たなかったんで、テーブル自体も新調することに。
ちなみにSQL Serverです。

Logs
id int
log_level char(5)
message nvarchar(255)
time_and_date datetime
Exceptions
id int
l_id int
name nvarchar(64)
StackTraces
id int
e_id int
line nvarchar(255)

こんな感じのテーブル。
全部のログが例外を持っているわけではないからテーブルとしては分割しておいた。
スタックトレースは直接入れてもよかったけど、ntext型は使いたくなかった*1んで、行ごとに分割してnvarchar(255)として入れることに。


で、Management Studioで直接ログを見るときは、

SELECT
    L.time_and_date AS '日時'
  , L.log_level     AS 'ログレベル'
  , L.message       AS 'メッセージ'
  , E.name          AS '例外クラス'
  , ST.line         AS 'スタックトレース'
FROM
    Logs L
      LEFT OUTER JOIN Exceptions E ON L.id = E.l_id
      LEFT OUTER JOIN StackTraces ST ON E.id = ST.e_id
ORDER BY
    L.id, E.id, ST.id

な感じでいいんだけど、誰々曰く「ログレベルとかメッセージとか、いちいち同じ内容のものが出てわかりにくい!スタックトレースもぶっちゃけ最後のあたりだけでいい!!」だそうで。
なら削ればいいじゃない、ということでこんなSQL

SELECT
    -- ログレベル
    -- 例外IDが同じで、自分より小さいIDがあるなら表示しない
    CASE WHEN
      EXISTS(SELECT * FROM StackTraces CST WHERE E.id = CST.e_id AND CST.id < ST.id)
    THEN ''
    ELSE L.log_level END AS 'ログレベル'
    -- メッセージ
    -- 例外IDが同じで、自分より小さいIDがあるなら表示しない
  , CASE WHEN
      EXISTS(SELECT * FROM StackTraces CST WHERE E.id = CST.e_id AND CST.id < ST.id)
    THEN ''
    ELSE L.message END AS 'メッセージ'
    -- 例外クラス
    -- 例外IDが同じで、自分より小さいIDがあるなら表示しない
    -- そもそも例外を持たないログの場合は「なし」と表示
  , CASE WHEN
      EXISTS(SELECT * FROM StackTraces CST WHERE E.id = CST.e_id AND CST.id < ST.id)
    THEN ''
    ELSE coalesce(E.name, 'なし') AS '例外クラス'
    -- スタックトレース(概要)
    -- スタックトレースの各行の後ろ32文字分を表示
    -- そもそもスタックトレースを持たないログの場合は「なし」と表示(NULLと文字列を連結しても結果はNULL)
  , coalesce('...' + right(ST.line, 32), 'なし') AS 'スタックトレース'
  , L.time_and_date AS '日時'
FROM
    Logs L
      LEFT OUTER JOIN Exceptions E ON L.id = E.l_id
      LEFT OUTER JOIN StackTraces ST ON E.id = ST.e_id
ORDER BY
    L.id, E.id, ST.id

それにしてもスタイルが定まらない・・・

*1:DBはSQL Server2000だけど、SQL Server2005のツールを使っているからいろいろと紛らわしくなる