summaryrefslogtreecommitdiff
path: root/script-beta/log.lua
blob: 6af189dcb5a903f34a672f04d8b0412eb89dbd52 (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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
local fs = require 'bee.filesystem'

local osTime         = os.time
local osClock        = os.clock
local osDate         = os.date
local ioOpen         = io.open
local tablePack      = table.pack
local tableConcat    = table.concat
local tostring       = tostring
local debugTraceBack = debug.traceback
local mathModf       = math.modf
local debugGetInfo   = debug.getinfo
local ioStdErr       = io.stderr

_ENV = nil

local m = {}

m.file = nil
m.startTime = osTime() - osClock()
m.size = 0
m.maxSize = 100 * 1024 * 1024

local function trimSrc(src)
    src = src:sub(m.prefixLen + 3, -5)
    src = src:gsub('^[/\\]+', '')
    src = src:gsub('[\\/]+', '.')
    return src
end

local function init_log_file()
    if not m.file then
        m.file = ioOpen(m.path, 'w')
        if not m.file then
            return
        end
        m.file:write('')
        m.file:close()
        m.file = ioOpen(m.path, 'ab')
        if not m.file then
            return
        end
        m.file:setvbuf 'no'
    end
end

local function pushLog(level, ...)
    if not m.path then
        return
    end
    if m.size > m.maxSize then
        return
    end
    local t = tablePack(...)
    for i = 1, t.n do
        t[i] = tostring(t[i])
    end
    local str = tableConcat(t, '\t', 1, t.n)
    if level == 'error' then
        str = str .. '\n' .. debugTraceBack(nil, 3)
    end
    local info = debugGetInfo(3, 'Sl')
    return m.raw(0, level, str, info.source, info.currentline, osClock())
end

function m.info(...)
    pushLog('info', ...)
end

function m.debug(...)
    pushLog('debug', ...)
end

function m.trace(...)
    pushLog('trace', ...)
end

function m.warn(...)
    pushLog('warn', ...)
end

function m.error(...)
    return pushLog('error', ...)
end

function m.raw(thd, level, msg, source, currentline, clock)
    if level == 'error' then
        ioStdErr:write(msg .. '\n')
    end
    init_log_file()
    if not m.file then
        return ''
    end
    local sec, ms = mathModf(m.startTime + clock)
    local timestr = osDate('%H:%M:%S', sec)
    local agl = ''
    if #level < 5 then
        agl = (' '):rep(5 - #level)
    end
    local buf
    if currentline == -1 then
        buf = ('[%s.%03.f][%s]%s[#%d]: %s\n'):format(timestr, ms * 1000, level, agl, thd, msg)
    else
        buf = ('[%s.%03.f][%s]%s[#%d:%s:%s]: %s\n'):format(timestr, ms * 1000, level, agl, thd, trimSrc(source), currentline, msg)
    end
    m.file:write(buf)
    m.size = m.size + #buf
    if m.size > m.maxSize then
        m.file:write('[REACH MAX SIZE]')
    end
    return buf
end

function m.init(root, path)
    local lastBuf
    if m.file then
        m.file:close()
        m.file = nil
        local file = ioOpen(m.path, 'rb')
        if file then
            lastBuf = file:read 'a'
            file:close()
        end
    end
    m.path = path:string()
    m.prefixLen = #root:string()
    m.size = 0
    if not fs.exists(path:parent_path()) then
        fs.create_directories(path:parent_path())
    end
    if lastBuf then
        init_log_file()
        if m.file then
            m.file:write(lastBuf)
            m.size = m.size + #lastBuf
        end
    end
end

return m