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
|
-- Singleton object to deal with log messages
class log
log: (message, tags, level) ->
tags = tags or {}
if not level
error("Level is required")
tag_rev = {tag,true for tag in *tags}
chunk =
level: level
time: os.clock!
message: message
tags: tag_rev
stream_pos = log.messages + 1
log.stream[stream_pos] = chunk
for tag in *tags
log.by_tags[tag] = log.by_tags[tag] or {}
table.insert(log.by_tags[tag], stream_pos)
log.by_level[level] = log.by_level[level] or {}
table.insert(log.by_level[level], stream_pos)
log.messages += 1
for observer in *log.observers
observer(chunk)
reset: ->
log.stream = {}
log.messages = 0
log.by_tags = {}
log.by_level = {}
log.observers = {}
info: (message, tags) ->
log.log(message, tags, "info")
warn: (message, tags) ->
log.log(message, tags, "warn")
error: (message, tags) ->
log.log(message, tags, "error")
panic: (message, tags) ->
log.log(message, tags, "panic")
observe: (callback) ->
table.insert(log.observers, callback)
of_level: (level, callback) ->
if not log.by_level[level]
return
for message_idx in *log.by_level[level]
callback(log.stream[message_idx])
of_tags: (tags, callback) ->
if type(tags) ~= "table"
tags = {tags}
first_tag = tags[1]
assert(type(first_tag) == "string", "tag was not a string, was a " .. type(first_tag))
if not first_tag
error("Must pass a tag")
if not log.by_tags[first_tag]
return
for message_idx in *log.by_tags[first_tag]
message = log.stream[message_idx]
suitable = true
for tag in *tags
if not message.tags[tag]
suitable = false
break
if suitable
callback(message)
log.reset()
log
|