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
|