summaryrefslogtreecommitdiff
path: root/Data/BuiltIn/Libraries/lua-addons/addons/libs/logger.lua
blob: b1fb36058a52739cf2f2277c9885d152e1ed3d45 (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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
--[[
This library provides a set of functions to aid in debugging.
]]

_libs = _libs or {}

require('strings')
require('chat')

local string, chat = _libs.strings, _libs.chat
local table = require('table')

local logger = {}

_libs.logger = logger

_raw = _raw or {}

-- Set up, based on addon.
logger.defaults = {}
logger.defaults.logtofile = false
logger.defaults.defaultfile = 'lua.log'
logger.defaults.logcolor = 207
logger.defaults.errorcolor = 167
logger.defaults.warningcolor = 200
logger.defaults.noticecolor = 160

--[[
    Local functions
]]

local arrstring
local captionlog

-- Returns a concatenated string list, separated by whitespaces, for the chat output function.
-- Converts any kind of object type to a string, so it's type-safe.
-- Concatenates all provided arguments with whitespaces.
function arrstring(...)
    local str = ''
    local args = {...}

    for i = 1, select('#', ...) do
        if i > 1 then
            str = str..' '
        end
        str = str .. tostring(args[i])
    end

    return str
end

-- Prints the arguments provided to the FFXI chatlog, in the same color used for Campaign/Bastion alerts and Kupower messages. Can be changed below.
function captionlog(msg, msgcolor, ...)
    local caption = table.concat({_addon and _addon.name, msg}, ' ')

    if #caption > 0 then
        if logger.settings.logtofile then
            flog(nil, caption .. ':', ...)
            return
        end
        caption = (caption .. ':'):color(msgcolor) .. ' '
    end

    local str = ''
    if select('#', ...) == 0 or ... == '' then
        str = ' '
    else
        str = arrstring(...):gsub('\t', (' '):rep(4))
    end

    for _, line in ipairs(str:split('\n')) do
        windower.add_to_chat(logger.settings.logcolor, caption .. windower.to_shift_jis(line) .. _libs.chat.controls.reset)
    end
end

function log(...)
    captionlog(nil, logger.settings.logcolor, ...)
end

_raw.error = error
function error(...)
    captionlog('Error', logger.settings.errorcolor, ...)
end

function warning(...)
    captionlog('Warning', logger.settings.warningcolor, ...)
end

function notice(...)
    captionlog('Notice', logger.settings.noticecolor, ...)
end

-- Prints the arguments provided to a file, analogous to log(...) in functionality.
-- If the first argument ends with '.log', it will print to that output file, otherwise to 'lua.log' in the addon directory.
function flog(filename, ...)
    filename = filename or logger.settings.defaultfile

    local fh, err = io.open(windower.addon_path..filename, 'a')
    if fh == nil then
        if err ~= nil then
            error('File error:', err)
        else
            error('File error:', 'Unknown error.')
        end
    else
        fh:write(os.date('%Y-%m-%d %H:%M:%S') .. '| ' .. arrstring(...) .. '\n')
        fh:close()
    end
end

-- Returns a string representation of a table in explicit Lua syntax: {...}
function table.tostring(t)
    if next(t) == nil then
        return '{}'
    end

    keys = keys or false

    -- Iterate over table.
    local tstr = ''
    local kt = {}
    k = 0
    for key in pairs(t) do
        k = k + 1
        kt[k] = key
    end
    table.sort(kt, function(x, y)
        if type(x) == 'number' and type(y) == 'string' then
            return true
        elseif type(x) == 'string' and type(y) == 'number' then
            return false
        end

        return x<y
    end)

    for i, key in ipairs(kt) do
        val = t[key]
        -- Check for nested tables
        if type(val) == 'table' then
            if val.tostring then
                valstr = val:tostring()
            else
                valstr = table.tostring(val)
            end
        else
            if type(val) == 'string' then
                valstr = '"' .. val .. '"'
            else
                valstr = tostring(val)
            end
        end

        -- Append to the string.
        if tonumber(key) then
            tstr = tstr .. valstr
        else
            tstr = tstr .. tostring(key) .. '=' .. valstr
        end

        -- Add comma, unless it's the last value.
        if next(kt, i) ~= nil then
            tstr = tstr .. ', '
        end
    end

    -- Output the result, enclosed in braces.
    return '{' .. tstr .. '}'
end

_meta = _meta or {}
_meta.T = _meta.T or {}
_meta.T.__tostring = table.tostring

-- Prints a string representation of a table in explicit Lua syntax: {...}
function table.print(t, keys)
    if t.tostring then
        log(t:tostring(keys))
    else
        log(table.tostring(t, keys))
    end
end

-- Returns a vertical string representation of a table in explicit Lua syntax, with every element in its own line:
--- {
---     ...
--- }
function table.tovstring(t, keys, indentlevel)
    if next(t) == nil then
        return '{}'
    end

    indentlevel = indentlevel or 0
    keys = keys or false

    local indent = (' '):rep(indentlevel*4)
    local tstr = '{\n'
    local kt = {}
    k = 0
    for key in pairs(t) do
        k = k + 1
        kt[k] = key
    end
    table.sort(kt, function(x, y)
        return type(x) ~= type(y) and type(x) == 'number' or type(x) == 'number' and type(y) == 'number' and x < y
    end)

    for i, key in pairs(kt) do
        val = t[key]
        
        local function sanitize(val)
            local ret
            if type(val) == 'string' then
                ret = '"' .. val:gsub('"','\\"') .. '"'
            else
                ret = tostring(val)
            end
            return ret
        end
        
        -- Check for nested tables
        if type(val) == 'table' then
            if val.tovstring then
                valstr = val:tovstring(keys, indentlevel + 1)
            else
                valstr = table.tovstring(val, keys, indentlevel + 1)
            end
        else
            valstr = sanitize(val)
        end

        -- Append one line with indent.
        if not keys and tonumber(key) then
            tstr = tstr .. indent .. '    ' .. '[' .. sanitize(key) .. ']=' .. valstr
        else
            tstr = tstr .. indent .. '    ' .. '[' .. sanitize(key) .. ']=' .. valstr
        end

        -- Add comma, unless it's the last value.
        if next(kt, i) ~= nil then
            tstr = tstr .. ', '
        end

        tstr = tstr .. '\n'
    end
    tstr = tstr .. indent .. '}'

    return tstr
end

-- Prints a vertical string representation of a table in explicit Lua syntax, with every element in its own line:
--- {
---     ...
--- }
function table.vprint(t, keys)
    if t.tovstring then
        log(t:tovstring(keys))
    else
        log(table.tovstring(t, keys))
    end
end

-- Load logger settings (has to be after the logging functions have been defined, so those work in the config and related files).
local config = require('config')

logger.settings = config.load('../libs/logger.xml', logger.defaults)

return logger

--[[
Copyright © 2013-2014, Windower
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
    * Neither the name of Windower nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Windower BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
]]