-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathRemoteLogger.ttslua
executable file
·95 lines (77 loc) · 3.63 KB
/
RemoteLogger.ttslua
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
require('ge_tts.License')
local TableUtils = require('ge_tts.TableUtils')
local Logger = require('ge_tts.Logger')
local Json = require('ge_tts.Json')
local MAX_RETRIES = 5
---@class ge_tts__RemoteLogger : ge_tts__Logger
---@class ge_tts__static_RemoteLogger : ge_tts__static_Logger
---@overload fun(url: string): ge_tts__RemoteLogger
local RemoteLogger = {}
---@type table<number, string>
local levelPrefixes = {
[Logger.ERROR] = 'ERROR: ',
[Logger.WARNING] = 'WARNING: ',
[Logger.INFO] = 'INFO: ',
[Logger.DEBUG] = 'DEBUG: ',
[Logger.VERBOSE] = 'VERBOSE: ',
}
-- RemoteLogger guarantees message order and batches messages rather than instantly sending an individual request per message, which may arrive out of
-- order. Failed request will be retried.
--
-- Note: The retry mechanism may cause duplicate messages to be logged depending on server implementation. Specifically there's an edge-case if the server
-- receives a request, logs the messages, but the connection drops before we receive a 200 status code. Generally this won't occur, however if it's a major
-- concern then the server could first respond 200, wait for TCP confirmation, *then* log the messages received in the request.
setmetatable(RemoteLogger, TableUtils.merge(getmetatable(Logger), {
---@param url string
__call = function(_, url)
local self = Logger()
---@type string[]
local queuedMessages = {}
local postingCount = 0
local retry = 0
local function pumpQueue()
if postingCount == 0 and #queuedMessages > 0 then
retry = retry + 1
if retry <= MAX_RETRIES then
local content = Json.encode({
messages=queuedMessages
})
postingCount = #queuedMessages
-- NOTE: We're completely abusing the semantics of the HTTP PUT verb. We absolutely should be POSTing, but TTS's WebRequest APIs are
-- without a doubt the worst attempt at writing a HTTP client that I've ever encountered. For some reason we can only POST URL encoded
-- forms (which quickly run into URI length constraints, hence is unusable) where as we can PUT an arbitrary string, so we make do.
WebRequest.put(url, content, function(request)
if request.is_error then
postingCount = 0
Wait.time(pumpQueue, retry * retry * 0.1)
elseif request.is_done then
local unpostedMessages = {}
for i=postingCount + 1, #queuedMessages do
table.insert(unpostedMessages, queuedMessages[i])
end
queuedMessages = unpostedMessages
postingCount = 0
retry = 0
pumpQueue()
end
end)
else
error("Failed to send remote log messages.")
postingCount = 0
retry = 0
end
end
end
---@param message string
---@param level number @One of Logger.ERROR, Logger.WARNING, Logger.INFO, Logger.DEBUG or Logger.VERBOSE
function self.log(message, level)
if level <= self.getFilterLevel() then
table.insert(queuedMessages, levelPrefixes[level] .. message)
pumpQueue()
end
end
return self
end,
__index = Logger,
}))
return RemoteLogger