aboutsummaryrefslogtreecommitdiff
path: root/logger.nim
blob: 48aedf29e4f990aae05d9b30f7796382c008f9c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# tickwatch
# Author: Euxane TRAN-GIRARD
# Licence: EUPL-1.2

import std/sugar
import std/math
import std/unicode
import std/times
import std/os


const
  TIMESTAMP_FORMAT = "yyyy-MM-dd HH:mmZZZ "
  SKIPPED_SYMBOL = "."
  UNKNOWN_SYMBOL = "!"
  NUMERIC_SYMBOLS* = "123456789".toRunes
  UNICODE_SYMBOLS* = "_▁▂▃▄▅▆▇█".toRunes


type Scale* = proc(val: float): float {.noSideEffect.}

proc indicator(symbols: seq[Rune], min, max, val: float, scale: Scale): Rune =
  let division = scale(max - min) / float(symbols.len)
  let bucket = int(scale(val - min) / division)
  symbols[bucket.clamp(0, symbols.len - 1)]

proc indicator*(symbols: seq[Rune], min, max, val: int, scale: Scale): Rune =
  symbols.indicator(min.float, max.float, val.float, scale)

func millisecond(t: DateTime): int =
  t.nanosecond div (1_000_000)

func msUntilNextSec(t: DateTime): int =
  1000 - t.millisecond + 1

proc puts(f: File, s: string) =
  f.write s
  f.flushFile

proc puts(f: File, r: Rune) =
  f.puts r.toUTF8

func formatTimestampDateTime*(dt: DateTime): string =
  dt.format(TIMESTAMP_FORMAT)

func formatTimestampUnix*(dt: DateTime): string =
  ($dt.toTime.toUnix) & " "

func formatTimestampNone*(dt: DateTime): string =
  ""

proc loop*(
  probe: (timeout: Duration) -> int,
  getSymbol: (int) -> Rune,
  timestampHeader: (DateTime) -> string,
) =
  while true:
    stdout.puts timestampHeader(now())

    for tick in 0..<60:
      let t = now()
      if tick < t.second:
        stdout.puts SKIPPED_SYMBOL
        continue

      let timeout = initDuration(milliseconds = t.msUntilNextSec)
      try:
        let val = probe(timeout)
        stdout.puts getSymbol(val)
      except CatchableError:
        stdout.puts UNKNOWN_SYMBOL

      let tAfter = now()
      if tAfter < t + timeout:
        sleep(tAfter.msUntilNextSec)

    stdout.puts "\n"

proc flushAndQuit*() {.noconv.} =
  stdout.puts "\n"
  quit(0)


when defined(test):
  import std/unittest
  import std/sequtils

  suite "logger":
    test "indicator value":
      proc id(val: float): float = val
      let indics = (0..30).mapIt(NUMERIC_SYMBOLS.indicator(5, 20, it, id))
      check indics.deduplicate(isSorted = true) == NUMERIC_SYMBOLS