Example

Log Entry

Structured application logs.

Parse operational logs into specific events, with a generic fallback for ordinary messages.

What it shows

  • Every event has a timestamp, log level, and optional thread.
  • Specific events expose details such as invoice number, HTTP method and path, duration, attempt count, or failure reason.
  • Duration, HttpMethod, LogLevel, and UTC offset parts have their own types.
  • Generic captures ordinary log lines after the more specific event patterns.

Try adding another ordinary log line, or extend one of the specialized events with a new stable detail.

Specs

spec.yml
$flags: 'FLEXIBLE_WHITESPACE'

HttpMethod: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']

RequestPath: '/[A-Za-z0-9_./-]+'

Number:
  Decimal: '(?<![:\d])\d+\.\d+'
  Integer: '\d+'

Date:
  $fields:
    year: { $type: Number::Integer, $match: '\d{4}' }
    month: { $type: Number::Integer, $match: '0[1-9]|1[0-2]' }
    day: { $type: Number::Integer, $match: '0[1-9]|[12]\d|3[01]' }
  $patterns: '#{year}-#{month}-#{day}'

Time:
  $fields:
    hour: { $type: Number::Integer, $match: '[01]\d|2[0-3]' }
    minute: { $type: Number::Integer, $match: '[0-5]\d' }
    second: { $type: Number::Integer, $match: '[0-5]\d' }
    milliseconds: { $type: Number::Integer, $match: '\d{3}' }
  $patterns: '#{hour}:#{minute}:#{second}(\.#{milliseconds})?'

UtcOffset:
  $types:
    OffsetSign: '[+-]'
  $fields:
    sign: OffsetSign
    hour: { $type: Number::Integer, $match: '[01]\d|2[0-3]' }
    minute: { $type: Number::Integer, $match: '[0-5]\d' }
  $patterns: '#{sign}#{hour}:#{minute}'

Timestamp:
  $fields:
    date: Date
    time: Time
    offset: UtcOffset
  $patterns: '#{date}T#{time}#{offset}'

LogLevel:
  Trace: 'TRACE'
  Debug: 'DEBUG'
  Info: 'INFO'
  Warn: 'WARN'
  Error: 'ERROR'
  Fatal: 'FATAL'

Duration:
  $fields:
    value: Number
  Milliseconds: '#{value} ms'
  Seconds: '#{value} seconds'

LogEntry:
  $types:
    String: '.+'
  $fields:
    timestamp: Timestamp
    level: LogLevel
    thread: String

  InvoiceSaveFailure:
    $fields:
      level: LogLevel::Error
      invoice: Number::Integer
      errorCode: Number::Integer
    $patterns: '#{timestamp} #{level}( \[#{thread}])? Disk full while saving invoice #{invoice} \(code #{errorCode}\)'

  InvoiceRetryScheduled:
    $fields:
      level: LogLevel::Info
      invoice: Number::Integer
    $patterns: '#{timestamp} #{level}( \[#{thread}])? Retry scheduled for invoice #{invoice}'

  SlowHttpRequest:
    $fields:
      level: LogLevel::Warn
      method: HttpMethod
      path: RequestPath
      duration: Duration::Milliseconds
    $patterns: '#{timestamp} #{level}( \[#{thread}])? Slow request: #{method} #{path} took #{duration}'

  DatabaseConnectionFailure:
    $fields:
      level: LogLevel::Error
      attempts: Number::Integer
      reason: String
    $patterns: '#{timestamp} #{level}( \[#{thread}])? Database connection failed after #{attempts} attempts: #{reason}'

  InvoiceGenerationCompleted:
    $fields:
      level: LogLevel::Debug
      invoiceCount: Number::Integer
      duration: Duration::Seconds
    $patterns: '#{timestamp} #{level}( \[#{thread}])? Generated #{invoiceCount} invoices in #{duration}'

  Generic:
    $fields:
      message: String
    $patterns: '#{timestamp} #{level}( \[#{thread}])? #{message}'
Try it liveOpen Log Entry in StudioTweak the spec, paste your own input, and see the parse tree update in real time.

Or browse other examples →