• Operand
  • can sell console.

gram:build

> ./config/nushell/log.nu

Lenses
(coming soon!)


source ./day.nu
source ./machine.nu

def "cache local" [label: list<string>, blob: any] {
  let node = [ ~ cache.local (
    [ (day) $label ] | flatten | str join "."
  ) ] | path join | path expand | tee { mkdir ($in | path dirname)}
  if not ($node | path exists) { echo $blob | save $node }
  open $node
}

def log --wrapped [
  command: string
  ...call
] { timeit {
  d -b rec-clone
  mkdir ~/disc/rec-clone/log
  let clock = clock; print $clock;
  let run = [ $command $call "|" print "\n" exit ] | flatten | str join ' '
  nu -e $run | tee { save -a $"~/disc/rec-clone/log/(day).($command).log" }
} }

def "log ping" --wrapped [
  --dura (-d): duration = 4sec
  command: string
  ...call
] { d -b rec-clone; loop {
  let clock = clock
  let run = ([ $command $call ] | flatten | str join ' ')
  let response = nu -e (
    cache local [$command nu] (
    [ "#!nu" $"($run) | to json -r | print" "exit" ] | str join "\n" ))

  [ ($clock) ($run) ] | to json -r | str replace -r "]$" $", ($response)]\n" |
    tee { save -a $"~/disc/rec-clone/log/(day).($command).jsonl" };

  print $clock; $response | from json | print; sleep $dura
} }

def index [ ...nodes: path ] { $nodes | each {
  let label = $in | into string | str replace '/' '-'
  cache local [(day) $label index json] (tree -s --du -J $in)
} }

def "log proxy" [
  name: string = share
  --label (-l): string
] { shell $m.base tail -f $"/var/lib/caddy/($name).log" |
    each { $in | split row "\n" | each { |call|
      let occurrence =  $call | from json |
      insert clock { $in.ts * 1000000000 | into int | into datetime | date to-timezone US/Eastern | format date '%Y-%m-%d c%H:%M' } |
      insert call { let r = $in.request;
        [ $"($r.remote_ip)"
          $":($r.remote_port) called ($r.method)"
          $"://($r.host)($r.uri)"
        ] | str join "\t" } |
      insert response { [
        $"($in.status) >"
        $"  ($in.size)b, in"
        $"($in.duration * 1000 * 1000 | into int) us"
      ] | str join "\t" } |
      insert headers { try { $in.request.headers |
        transpose label shape |
        upsert shape {|header| try {$header.shape.0 | split row "," | str join "\n" } catch { $header.shape } }
        } catch { $in.request.headers }
      }

      # check and summarize common cases.
      print (
      if ($occurrence.headers | where label == 'User-Agent' and shape =~ "Uptime-Kuma" | length) > 0 {
        { ping: $"[($occurrence.clock)] ($occurrence.call)" }
      } else if (not ($label | is-empty) and ($occurrence.level != $label)) {
        { label: $occurrence.level }
      } else {
        $occurrence | select clock call response headers
      } | table -e)
} }; null }

# use alongside docker.
def "log ship" [ machine: record, --place (-p): string ] {
  d -b rec-clone
  let p = $place | path basename
  mkdir ($"~/disc/rec-clone/log/daily/($p)/" | path expand)
  proxy $machine docker $"compose -f ($place)/docker-compose.y*ml logs" |
    save -a $"~/disc/rec-clone/log/daily/($p)/(day).($p)-op.log"
}