tailtales 0.2.3

Flexible log viewer for logfmt and other formats with LUA scripting, filtering, filtering expressions, and real-time pipe following.
Documentation
# colors:
#  * black
#  * red
#  * green
#  * yellow
#  * blue
#  * magenta
#  * cyan
#  * gray
#  * darkgray
#  * lightred
#  * lightgreen
#  * lightyellow
#  * lightblue
#  * lightmagenta
#  * lightcyan
#  * white

global:
  reload_on_truncate: false
  gutter_symbol: "" # I like this one as it allows to have two colors (front and back)
  # gutter_symbol: "█"
  # gutter_symbol: "♥"
  # gutter_symbol: "✔"
  # gutter_symbol: "│"

  symbols:
    # https://github.com/ryanoasis/powerline-extra-symbols
    # with nerd fonts. Change this if they do not look right.
    tag_initial: "\ue0b8" # Symbol before label in footer tags
    tag_mid_left: " \ue0be" # Symbol between label and value in footer tags
    tag_mid_right: " " # Symbol between value and end in footer tags
    tag_end: " \ue0be\ue0b8" # Symbol after value in footer tags
    # Alternative ASCII-friendly symbols:
    # tag_initial: "["
    # tag_mid_left: " :"
    # tag_mid_right: " "
    # tag_end: "]"

colors:
  normal: white black
  highlight: white darkgray
  mark: yellow black
  mark_highlight: black yellow
  table:
    header: black lightgreen
  details:
    title: white black
    key: green black
    value: yellow black
    border: green black
  footer:
    command: cyan black
    filter: yellow black
    search: magenta black
    version: blue black
    rule: green black
    other: cyan black
    line_number: blue black

# If called without any argument, this is what it opens.
# With ! at the begining it will execute the command with the rest of the argumments
default_arguments:
  - "!journalctl"
  - -f
  - --since
  - today
  - -o
  - short-iso

keybindings:
  ":": "mode('command')"
  "=": "warning('Line: ' .. (get_position() + 1))"
  "|": "mode('filter')"
  "f": "mode('filter')"
  "/": "mode('search')"
  "n": "search_next()"
  "shift-n": "search_prev()"
  "control-del": "clear_records()"
  "control-l": "refresh_screen()"
  "F1": "exec('xdg-open https://github.com/davidmoreno/tailtales/#use'); warning('Opened documentation')"
  "F2": "exec('xdg-open https://www.perplexity.ai/search/new?q=' .. url_encode(get_record().original)); warning('Opened Perplexity')"
  "F3": "exec('xdg-open https://www.duckduckgo.com/?q=' .. url_encode(get_record().original)); warning('Opened DuckDuckGo')"
  "F4": "exec('xdg-open https://google.com/search?q=' .. url_encode(get_record().original)); warning('Opened Google')"
  "F12": "lua_repl()"
  "q": "quit()"
  "control-c": |
    local record = get_record()
    local success = exec('wl-copy "' .. escape_shell(record.original) .. '"')
    if not success then
      exec('echo "' .. escape_shell(record.original) .. '" | xclip -i -selection clipboard')
    end
    warning("Line copied to clipboard")
  "j": "vmove(1)"
  "k": "vmove(-1)"
  "up": "vmove(-1)"
  "down": "vmove(1)"
  "page up": "vmove(-10)"
  "page down": "vmove(10)"
  "left": "hmove(-1)"
  "right": "hmove(1)"
  "control-left": "hmove(-10)"
  "control-right": "hmove(10)"
  "home": "vgoto(1)"
  "end": "vgoto(0)" # 0 is the last line
  " ": "toggle_mark('yellow')"
  "1": "toggle_mark('red')"
  "2": "toggle_mark('green')"
  "3": "toggle_mark('blue')"
  "4": "toggle_mark('magenta')"
  "5": "toggle_mark('cyan')"
  "tab": "move_to_next_mark()"
  "shift-back tab": "move_to_prev_mark()"
  "esc": "mode('normal')"
  "v": "toggle_details()"
  "g": |
    local line_str = ask("Go to line number:")
    local line_num = tonumber(line_str)
    if line_num then
      vgoto(line_num)
      warning("Moved to line " .. line_num)
    else
      warning("Invalid line number: " .. line_str)
    end

# Uses the file_patterns to determine which rules to apply
# Can be expanded at your ~/.config/tailtales/settings.yaml
rules:
  - name: apache
    file_patterns:
      - access\.log
      - apache/.*\.log
    extractors:
      # Common Log Format, see http://httpd.apache.org/docs/2.0/logs.html#common
      #  127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
      - pattern <ip> - <user> [<timestamp>] "<method> <url> <protocol>" <status> <bytes>
      # - transform timestamp iso8601
    filters:
      - name: errors
        expression: status >= 500
        highlight: red
      - name: not_found
        expression: status == 404
        highlight: yellow
      - name: successful
        expression: status == 200
        highlight: green
      - name: redirect
        expression: status == 304
        highlight: blue
      - name: empty requests
        expression: bytes == 0
        highlight: red
    columns:
      - name: timestamp
        width: 25
      - name: ip
        width: 15
      - name: method
        width: 5
      - name: url
        width: 30
      - name: protocol
        width: 10
      - name: status
        width: 5
      - name: bytes
        width: 10
        align: right

  - name: dpkg
    file_patterns:
      - dpkg\.log
    extractors:
      - regex (?P<timestamp>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) (?P<action>startup archives unpack|upgrade|status half-configured|status unpacked|status half installed|status triggers pending|configure)
      - regex (?P<package>[\w\d\.-]+):(?P<arch>\w+) (?P<version>\d.*)
    columns:
      - name: line_number
        width: 6
        align: right
      - name: action
        width: 16
      - name: package
        width: 16
      - name: version
        width: 8

  - name: nginx
    file_patterns:
      - nginx/\*\.log
    extractors:
      # 127.0.0.1 - - [02/Jan/2024:12:10:46 +0100] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0"
      - pattern <ip> - <user> [<timestamp>] "<method> <url> <protocol>" <status> <bytes> "<referer>" "<user_agent>"
      - transform timestamp iso8601
    filters:
      - name: errors
        expression: status ~ "5\d\d"
        highlight: white red
      - name: not_found
        expression: status == 404
        highlight: white yellow
      - name: successful
        expression: status == 200
        highlight: white green
      - name: too big
        expression: bytes > 1000000
      - name: empty requests
        expression: bytes == 0

  - name: json
    file_patterns:
      - .*\.json
    extractors:
      - json
    filters:
      - highlight: white red
        expression: level == "error"
      - highlight: white yellow
        expression: level == "warning"
      - highlight: white green
        expression: level == "info"

  - name: django
    file_patterns:
      - django/.*\.log
    extractors:
      - pattern <timestamp> <level> <module> <message>
      - logfmt
      - transform timestamp iso8601
    filters:
      - name: errors
        expression: level == "ERROR"
        highlight: white red
      - name: warnings
        expression: level == "WARNING"
        highlight: white yellow
      - name: infos
        expression: level == "INFO"
        highlight: white green
      - name: debug
        expression: level == "DEBUG"
        highlight: white blue

  - name: journald
    file_patterns:
      - /var/log/journal/
      - "!journalctl"
    extractors:
      - "pattern <timestamp> <hostname> <service>: <_>"
      - logfmt
    filters:
      - name: kernel
        expression: "kernel"
        gutter: yellow
        gutter_symbol: "\ue712"
      - name: systemd
        expression: "systemd"
        gutter: yellow
        gutter_symbol: ""
      - name: mozilla
        expression: "mozilla"
        gutter: red
        gutter_symbol: ""
      - name: pipewire
        expression: "pipewire"
        gutter: blue
        gutter_symbol: ""

  - name: csv
    file_patterns:
      - .*\.csv
    extractors:
      - csv

  - name: default
    file_patterns:
      - ".*"
    extractors:
      - logfmt
      # - json
      - regex (?P<timestamp>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})
      - regex (?P<timestamp>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z)
      - regex (?P<level>info|warning|error|debug|warn)
      - regex (?P<date>\d{4}-\d{2}-\d{2})
      - regex (?P<what>status|upgrade|startup)
      - autodatetime
    filters:
      - name: errors
        expression: "error"
        gutter: red
      - name: warnings
        expression: "warning"
        gutter: yellow
      - name: warn
        expression: "warn"
        gutter: yellow
      - name: infos
        expression: "info"
        gutter: green
      - name: debug
        expression: "debug"
        gutter: blue