Class: Llv::Parser
- Inherits:
-
Object
- Object
- Llv::Parser
- Defined in:
- lib/llv/parser.rb
Overview
Turns a raw log line into a structured Event. Stateful per-stream so that untagged HTTP lines (when the host app hasn’t configured ‘config.log_tags = [:request_id]`) can still be grouped via Started/Completed bracketing.
Defined Under Namespace
Classes: Event
Constant Summary collapse
- TAG_RE =
Rails::TaggedLogging emits “[tag] ” (single space) for each tag, so we only consume one space after each bracket — anything more is the message’s own indentation and is meaningful for classification.
/\A(\[[^\]]*\] )+/- UUID_RE =
/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/- CLASSIFIERS =
[ [ :request_started, # The optional bracketed segment matches `[WebSocket]` for ActionCable # upgrade lines and similar transport markers Rails sometimes emits. /\AStarted\s+(?<method>[A-Z]+)\s+"(?<path>[^"]+)"(?:\s+\[[^\]]+\])?\s+for\s+(?<ip>\S+)\s+at\s+(?<at>.+)\z/ ], [ :processing, /\AProcessing by\s+(?<controller>\S+)\s+as\s+(?<format>\S+)\z/ ], [ :parameters, /\A\s*Parameters:\s*(?<params>.+)\z/ ], [ :sql_source, /\A\s*↳\s+(?<source>.+)\z/ ], [ :sql, /\A\s+(?<label>[A-Z][A-Za-z0-9_:]*\s+(?:Load|Count|Exists\??|Pluck|Update|Insert|Create|Destroy|Delete|Maximum|Minimum|Sum|Average))\s+\((?<duration>[\d.]+)(?<unit>ms|s)\)\s+(?<query>.+)\z/ ], [ :sql, /\A\s+(?<label>SQL|TRANSACTION|SCHEMA|CACHE)\s+\((?<duration>[\d.]+)(?<unit>ms|s)\)\s+(?<query>.+)\z/ ], [ :render, /\A\s*Rendered\s+(?<template>.+)\z/ ], [ :cache, /\ACACHE\s+(?<result>HIT|MISS)\s+(?<key>.+)\z/ ], [ :request_completed, /\ACompleted\s+(?<status>\d+)\s+(?<status_text>[A-Za-z ]+?)\s+in\s+(?<duration_ms>[\d.]+)ms(?:\s+\((?<details>[^)]+)\))?/ ], [ :job_enqueued, /\AEnqueued\s+(?<job>\S+)\s+\(Job ID:\s+(?<job_id>[\w-]+)\)\s+to\s+(?<adapter>[^(]+)\((?<queue>[^)]+)\)/ ], [ :job_performing, /\APerforming\s+(?<job>\S+)\s+\(Job ID:\s+(?<job_id>[\w-]+)\)\s+from\s+(?<adapter>[^(]+)\((?<queue>[^)]+)\)/ ], [ :job_performed, /\APerformed\s+(?<job>\S+)\s+\(Job ID:\s+(?<job_id>[\w-]+)\)\s+from\s+(?<adapter>[^(]+)\((?<queue>[^)]+)\)\s+in\s+(?<duration_ms>[\d.]+)ms/ ], [ :job_retry_stopped, /\AStopped retrying\s+(?<job>\S+)\s+\(Job ID:\s+(?<job_id>[\w-]+)\)/ ] ].freeze
Instance Method Summary collapse
-
#initialize ⇒ Parser
constructor
A new instance of Parser.
- #parse(raw_line) ⇒ Object
Constructor Details
#initialize ⇒ Parser
Returns a new instance of Parser.
85 86 87 88 |
# File 'lib/llv/parser.rb', line 85 def initialize @untagged_seq = 0 @open_untagged_http = nil end |
Instance Method Details
#parse(raw_line) ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/llv/parser.rb', line 90 def parse(raw_line) raw = raw_line.chomp plain = Ansi.strip(raw) tag_match = plain.match(TAG_RE) tag_prefix_len = tag_match ? tag_match[0].length : 0 = tag_match ? tag_match[0].scan(/\[([^\]]*)\]/).flatten : [] raw_body = raw[tag_prefix_len..] || "" plain_body = plain[tag_prefix_len..] || "" group_id, group_kind, title = identify_group() type, payload = classify(plain_body) group_id, group_kind, title = adjust_for_untagged(group_id, group_kind, title, type, payload) title ||= derive_title(type, payload) # An HTTP request to /cable is ActionCable. Treat it as its own kind so # the UI can filter it out — these connections are long-lived and noisy. if group_kind == :http && cable_path?(title, payload) group_kind = :cable end Event.new( group_id: group_id, group_kind: group_kind, group_title: title, type: type, payload: payload, raw: raw_body, plain: plain_body ) end |