summaryrefslogtreecommitdiff
path: root/server/src/log.lua
blob: 7ebb55cf966197750dbaa5e91099528ca29672b6 (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
local fs = require 'bee.filesystem'

local log = {}

log.file = nil
log.start_time = os.time() - os.clock()
log.size = 0
log.max_size = 100 * 1024 * 1024

local function trim_src(src)
    src = src:sub(log.prefix_len + 1, -5)
    src = src:gsub('^[/\\]+', '')
    src = src:gsub('[\\/]+', '.')
    return src
end

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

local function push_log(level, ...)
    if not log.path then
        return
    end
    if log.size > log.max_size then
        return
    end
    local t = table.pack(...)
    for i = 1, t.n do
        t[i] = tostring(t[i])
    end
    local str = table.concat(t, '\t', 1, t.n)
    if level == 'error' then
        str = str .. '\n' .. debug.traceback(nil, 3)
        io.stderr:write(str .. '\n')
    end
    init_log_file()
    if not log.file then
        return
    end
    local sec, ms = math.modf(log.start_time + os.clock())
    local timestr = os.date('%Y-%m-%d %H:%M:%S', sec)
    local info = debug.getinfo(3, 'Sl')
    local buf
    if info and info.currentline > 0 then
        buf = ('[%s.%03.f][%s]: [%s:%s]%s\n'):format(timestr, ms * 1000, level, trim_src(info.source), info.currentline, str)
    else
        buf = ('[%s.%03.f][%s]: %s\n'):format(timestr, ms * 1000, level, str)
    end
    log.file:write(buf)
    log.size = log.size + #buf
    if log.size > log.max_size then
        log.file:write('[REACH MAX SIZE]')
    end
    return str
end

function log.info(...)
    push_log('info', ...)
end

function log.debug(...)
    push_log('debug', ...)
end

function log.trace(...)
    push_log('trace', ...)
end

function log.warn(...)
    push_log('warn', ...)
end

function log.error(...)
    return push_log('error', ...)
end

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

return log