@larablox/monolog 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/Monolog/Attribute/AsMonologProcessor.d.ts +30 -0
- package/out/Monolog/Attribute/AsMonologProcessor.luau +59 -0
- package/out/Monolog/Attribute/WithMonologChannel.d.ts +18 -0
- package/out/Monolog/Attribute/WithMonologChannel.luau +33 -0
- package/out/Monolog/Formatter/FormatterInterface.d.ts +8 -0
- package/out/Monolog/Formatter/FormatterInterface.luau +3 -0
- package/out/Monolog/Formatter/HtmlFormatter.d.ts +23 -0
- package/out/Monolog/Formatter/HtmlFormatter.luau +128 -0
- package/out/Monolog/Formatter/JsonFormatter.d.ts +34 -0
- package/out/Monolog/Formatter/JsonFormatter.luau +114 -0
- package/out/Monolog/Formatter/LineFormatter.d.ts +52 -0
- package/out/Monolog/Formatter/LineFormatter.luau +228 -0
- package/out/Monolog/Formatter/NormalizerFormatter.d.ts +87 -0
- package/out/Monolog/Formatter/NormalizerFormatter.luau +214 -0
- package/out/Monolog/Formatter/ScalarFormatter.d.ts +19 -0
- package/out/Monolog/Formatter/ScalarFormatter.luau +53 -0
- package/out/Monolog/Handler/AbstractHandler.d.ts +22 -0
- package/out/Monolog/Handler/AbstractHandler.luau +50 -0
- package/out/Monolog/Handler/AbstractProcessingHandler.d.ts +30 -0
- package/out/Monolog/Handler/AbstractProcessingHandler.luau +79 -0
- package/out/Monolog/Handler/Handler.d.ts +15 -0
- package/out/Monolog/Handler/Handler.luau +25 -0
- package/out/Monolog/Handler/HandlerInterface.d.ts +12 -0
- package/out/Monolog/Handler/HandlerInterface.luau +3 -0
- package/out/Monolog/Handler/NullHandler.d.ts +10 -0
- package/out/Monolog/Handler/NullHandler.luau +36 -0
- package/out/Monolog/Handler/RobloxConsoleHandler.d.ts +55 -0
- package/out/Monolog/Handler/RobloxConsoleHandler.luau +141 -0
- package/out/Monolog/Handler/TestHandler.d.ts +90 -0
- package/out/Monolog/Handler/TestHandler.luau +288 -0
- package/out/Monolog/Level.d.ts +38 -0
- package/out/Monolog/Level.luau +119 -0
- package/out/Monolog/LogRecord.d.ts +43 -0
- package/out/Monolog/LogRecord.luau +77 -0
- package/out/Monolog/Logger.d.ts +93 -0
- package/out/Monolog/Logger.luau +248 -0
- package/out/Monolog/LoggerInterface.d.ts +33 -0
- package/out/Monolog/LoggerInterface.luau +15 -0
- package/out/Monolog/Processor/ClosureContextProcessor.d.ts +13 -0
- package/out/Monolog/Processor/ClosureContextProcessor.luau +76 -0
- package/out/Monolog/Processor/IntrospectionProcessor.d.ts +33 -0
- package/out/Monolog/Processor/IntrospectionProcessor.luau +69 -0
- package/out/Monolog/Processor/MemoryPeakUsageProcessor.d.ts +17 -0
- package/out/Monolog/Processor/MemoryPeakUsageProcessor.luau +49 -0
- package/out/Monolog/Processor/MemoryProcessor.d.ts +20 -0
- package/out/Monolog/Processor/MemoryProcessor.luau +41 -0
- package/out/Monolog/Processor/MemoryUsageProcessor.d.ts +12 -0
- package/out/Monolog/Processor/MemoryUsageProcessor.luau +38 -0
- package/out/Monolog/Processor/ProcessIdProcessor.d.ts +13 -0
- package/out/Monolog/Processor/ProcessIdProcessor.luau +33 -0
- package/out/Monolog/Processor/ProcessorInterface.d.ts +13 -0
- package/out/Monolog/Processor/ProcessorInterface.luau +20 -0
- package/out/Monolog/Processor/PsrLogMessageProcessor.d.ts +12 -0
- package/out/Monolog/Processor/PsrLogMessageProcessor.luau +62 -0
- package/out/Monolog/Processor/TagProcessor.d.ts +12 -0
- package/out/Monolog/Processor/TagProcessor.luau +46 -0
- package/out/Monolog/Processor/UidProcessor.d.ts +18 -0
- package/out/Monolog/Processor/UidProcessor.luau +53 -0
- package/out/Monolog/Registry.d.ts +21 -0
- package/out/Monolog/Registry.luau +86 -0
- package/out/Monolog/ResettableInterface.d.ts +11 -0
- package/out/Monolog/ResettableInterface.luau +21 -0
- package/out/Monolog/Test/MonologTestCase.d.ts +26 -0
- package/out/Monolog/Test/MonologTestCase.luau +73 -0
- package/out/Monolog/Test/TestCase.d.ts +4 -0
- package/out/Monolog/Test/TestCase.luau +25 -0
- package/out/Monolog/Utils.d.ts +21 -0
- package/out/Monolog/Utils.luau +181 -0
- package/out/index.d.ts +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local _Level = TS.import(script, script.Parent, "Level")
|
|
4
|
+
local Level = _Level.Level
|
|
5
|
+
local Levels = _Level.Levels
|
|
6
|
+
local LogRecord = TS.import(script, script.Parent, "LogRecord").LogRecord
|
|
7
|
+
local isResettable = TS.import(script, script.Parent, "ResettableInterface").isResettable
|
|
8
|
+
local runProcessor = TS.import(script, script.Parent, "Processor", "ProcessorInterface").runProcessor
|
|
9
|
+
--* PHP: `Closure` passed to `Logger::setExceptionHandler()`.
|
|
10
|
+
--* PHP: `Logger::RFC_5424_LEVELS`, reversed (RFC 5424 number -> Monolog `Level`).
|
|
11
|
+
local RFC_5424_LEVELS = {
|
|
12
|
+
[7] = Level.Debug,
|
|
13
|
+
[6] = Level.Info,
|
|
14
|
+
[5] = Level.Notice,
|
|
15
|
+
[4] = Level.Warning,
|
|
16
|
+
[3] = Level.Error,
|
|
17
|
+
[2] = Level.Critical,
|
|
18
|
+
[1] = Level.Alert,
|
|
19
|
+
[0] = Level.Emergency,
|
|
20
|
+
}
|
|
21
|
+
--[[
|
|
22
|
+
*
|
|
23
|
+
* PHP: `Monolog\Logger`.
|
|
24
|
+
*
|
|
25
|
+
* Holds the handler stack and the processor stack, builds a `LogRecord` and
|
|
26
|
+
* walks the handlers until one stops the bubbling chain.
|
|
27
|
+
*
|
|
28
|
+
* Not ported: timezones and microsecond timestamps (`os.time` is what a place
|
|
29
|
+
* has) and the serialization hooks (`__serialize`/`__unserialize`, no PHP
|
|
30
|
+
* magic serialization here). The infinite-logging-loop guard is kept, but
|
|
31
|
+
* keyed by a single instance counter rather than a `Fiber`-keyed `WeakMap` --
|
|
32
|
+
* there is no fiber concept on this platform.
|
|
33
|
+
|
|
34
|
+
]]
|
|
35
|
+
local Logger
|
|
36
|
+
do
|
|
37
|
+
Logger = setmetatable({}, {
|
|
38
|
+
__tostring = function()
|
|
39
|
+
return "Logger"
|
|
40
|
+
end,
|
|
41
|
+
})
|
|
42
|
+
Logger.__index = Logger
|
|
43
|
+
function Logger.new(...)
|
|
44
|
+
local self = setmetatable({}, Logger)
|
|
45
|
+
return self:constructor(...) or self
|
|
46
|
+
end
|
|
47
|
+
function Logger:constructor(name, handlers, processors)
|
|
48
|
+
if handlers == nil then
|
|
49
|
+
handlers = {}
|
|
50
|
+
end
|
|
51
|
+
if processors == nil then
|
|
52
|
+
processors = {}
|
|
53
|
+
end
|
|
54
|
+
self.name = name
|
|
55
|
+
self.handlers = {}
|
|
56
|
+
self.processors = {}
|
|
57
|
+
self.logDepth = 0
|
|
58
|
+
self:setHandlers(handlers)
|
|
59
|
+
for _, processor in processors do
|
|
60
|
+
local _exp = self.processors
|
|
61
|
+
table.insert(_exp, processor)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
function Logger:getName()
|
|
65
|
+
return self.name
|
|
66
|
+
end
|
|
67
|
+
function Logger:withName(name)
|
|
68
|
+
return Logger.new(name, self.handlers, self.processors)
|
|
69
|
+
end
|
|
70
|
+
function Logger:pushHandler(handler)
|
|
71
|
+
local _handlers = self.handlers
|
|
72
|
+
local _handler = handler
|
|
73
|
+
table.insert(_handlers, 1, _handler)
|
|
74
|
+
return self
|
|
75
|
+
end
|
|
76
|
+
function Logger:popHandler()
|
|
77
|
+
return table.remove(self.handlers, 1)
|
|
78
|
+
end
|
|
79
|
+
function Logger:setHandlers(handlers)
|
|
80
|
+
table.clear(self.handlers)
|
|
81
|
+
for index = #handlers - 1, 0, -1 do
|
|
82
|
+
self:pushHandler(handlers[index + 1])
|
|
83
|
+
end
|
|
84
|
+
return self
|
|
85
|
+
end
|
|
86
|
+
function Logger:getHandlers()
|
|
87
|
+
return self.handlers
|
|
88
|
+
end
|
|
89
|
+
function Logger:pushProcessor(processor)
|
|
90
|
+
local _processors = self.processors
|
|
91
|
+
local _processor = processor
|
|
92
|
+
table.insert(_processors, 1, _processor)
|
|
93
|
+
return self
|
|
94
|
+
end
|
|
95
|
+
function Logger:popProcessor()
|
|
96
|
+
return table.remove(self.processors, 1)
|
|
97
|
+
end
|
|
98
|
+
function Logger:getProcessors()
|
|
99
|
+
return self.processors
|
|
100
|
+
end
|
|
101
|
+
function Logger:addRecord(level, message, context)
|
|
102
|
+
if context == nil then
|
|
103
|
+
context = {}
|
|
104
|
+
end
|
|
105
|
+
self.logDepth += 1
|
|
106
|
+
local handled = self:addRecordAtDepth(Logger:remapRFC5424(level), message, context)
|
|
107
|
+
self.logDepth -= 1
|
|
108
|
+
return handled
|
|
109
|
+
end
|
|
110
|
+
function Logger:addRecordAtDepth(level, message, context)
|
|
111
|
+
if self.logDepth == 3 then
|
|
112
|
+
self:warning("A possible infinite logging loop was detected and aborted. It appears some of your handler code is triggering logging, see the previous log record for a hint as to what may be the cause.")
|
|
113
|
+
return false
|
|
114
|
+
elseif self.logDepth >= 5 then
|
|
115
|
+
-- log depth 4 is let through, so we can log the warning above
|
|
116
|
+
return false
|
|
117
|
+
end
|
|
118
|
+
local record = LogRecord.new(os.time(), self.name, Logger:toMonologLevel(level), message, context, {})
|
|
119
|
+
local recordInitialized = #self.processors == 0
|
|
120
|
+
local handled = false
|
|
121
|
+
for _, handler in self.handlers do
|
|
122
|
+
if not recordInitialized then
|
|
123
|
+
-- Skip initializing the record as long as no handler will take it.
|
|
124
|
+
if not handler:isHandling(record) then
|
|
125
|
+
continue
|
|
126
|
+
end
|
|
127
|
+
local processedOk, processedResult = pcall(function()
|
|
128
|
+
local processed = record
|
|
129
|
+
for _1, processor in self.processors do
|
|
130
|
+
processed = runProcessor(processor, processed)
|
|
131
|
+
end
|
|
132
|
+
return processed
|
|
133
|
+
end)
|
|
134
|
+
if not processedOk then
|
|
135
|
+
self:handleException(processedResult, record)
|
|
136
|
+
return true
|
|
137
|
+
end
|
|
138
|
+
record = processedResult
|
|
139
|
+
recordInitialized = true
|
|
140
|
+
end
|
|
141
|
+
handled = true
|
|
142
|
+
local handledOk, handledResult = pcall(function()
|
|
143
|
+
return handler:handle(record:clone())
|
|
144
|
+
end)
|
|
145
|
+
if not handledOk then
|
|
146
|
+
self:handleException(handledResult, record)
|
|
147
|
+
return true
|
|
148
|
+
end
|
|
149
|
+
if handledResult == true then
|
|
150
|
+
break
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
return handled
|
|
154
|
+
end
|
|
155
|
+
function Logger:toMonologLevel(level)
|
|
156
|
+
local _level = level
|
|
157
|
+
if not (type(_level) == "string") then
|
|
158
|
+
return level
|
|
159
|
+
end
|
|
160
|
+
local found = Levels:fromName(level)
|
|
161
|
+
if found == nil then
|
|
162
|
+
error(`Level "{level}" is not defined, use one of: {table.concat(Levels.NAMES, ", ")}`)
|
|
163
|
+
end
|
|
164
|
+
return found
|
|
165
|
+
end
|
|
166
|
+
function Logger:remapRFC5424(level)
|
|
167
|
+
local _level = level
|
|
168
|
+
local _condition = type(_level) == "number"
|
|
169
|
+
if _condition then
|
|
170
|
+
local _level_1 = level
|
|
171
|
+
_condition = RFC_5424_LEVELS[_level_1] ~= nil
|
|
172
|
+
end
|
|
173
|
+
if _condition then
|
|
174
|
+
local _level_1 = level
|
|
175
|
+
return RFC_5424_LEVELS[_level_1]
|
|
176
|
+
end
|
|
177
|
+
return level
|
|
178
|
+
end
|
|
179
|
+
function Logger:isHandling(level)
|
|
180
|
+
local record = LogRecord.new(os.time(), self.name, Logger:toMonologLevel(level), "")
|
|
181
|
+
for _, handler in self.handlers do
|
|
182
|
+
if handler:isHandling(record) then
|
|
183
|
+
return true
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
return false
|
|
187
|
+
end
|
|
188
|
+
function Logger:setExceptionHandler(callback)
|
|
189
|
+
self.exceptionHandler = callback
|
|
190
|
+
return self
|
|
191
|
+
end
|
|
192
|
+
function Logger:getExceptionHandler()
|
|
193
|
+
return self.exceptionHandler
|
|
194
|
+
end
|
|
195
|
+
function Logger:handleException(error_, record)
|
|
196
|
+
if self.exceptionHandler == nil then
|
|
197
|
+
error(error_)
|
|
198
|
+
end
|
|
199
|
+
self.exceptionHandler(error_, record)
|
|
200
|
+
end
|
|
201
|
+
function Logger:close()
|
|
202
|
+
for _, handler in self.handlers do
|
|
203
|
+
handler:close()
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
function Logger:reset()
|
|
207
|
+
for _, handler in self.handlers do
|
|
208
|
+
if isResettable(handler) then
|
|
209
|
+
handler:reset()
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
for _, processor in self.processors do
|
|
213
|
+
if isResettable(processor) then
|
|
214
|
+
processor:reset()
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
function Logger:emergency(message, context)
|
|
219
|
+
self:addRecord(Level.Emergency, tostring(message), context or {})
|
|
220
|
+
end
|
|
221
|
+
function Logger:alert(message, context)
|
|
222
|
+
self:addRecord(Level.Alert, tostring(message), context or {})
|
|
223
|
+
end
|
|
224
|
+
function Logger:critical(message, context)
|
|
225
|
+
self:addRecord(Level.Critical, tostring(message), context or {})
|
|
226
|
+
end
|
|
227
|
+
function Logger:error(message, context)
|
|
228
|
+
self:addRecord(Level.Error, tostring(message), context or {})
|
|
229
|
+
end
|
|
230
|
+
function Logger:warning(message, context)
|
|
231
|
+
self:addRecord(Level.Warning, tostring(message), context or {})
|
|
232
|
+
end
|
|
233
|
+
function Logger:notice(message, context)
|
|
234
|
+
self:addRecord(Level.Notice, tostring(message), context or {})
|
|
235
|
+
end
|
|
236
|
+
function Logger:info(message, context)
|
|
237
|
+
self:addRecord(Level.Info, tostring(message), context or {})
|
|
238
|
+
end
|
|
239
|
+
function Logger:debug(message, context)
|
|
240
|
+
self:addRecord(Level.Debug, tostring(message), context or {})
|
|
241
|
+
end
|
|
242
|
+
function Logger:log(level, message, context)
|
|
243
|
+
self:addRecord(Logger:toMonologLevel(Logger:remapRFC5424(level)), tostring(message), context or {})
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
return {
|
|
247
|
+
Logger = Logger,
|
|
248
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** PHP: the levels `Psr\Log\LogLevel` defines, in ascending severity. */
|
|
2
|
+
export type LogLevel = "debug" | "info" | "notice" | "warning" | "error" | "critical" | "alert" | "emergency";
|
|
3
|
+
/** PHP: `array $context`. */
|
|
4
|
+
export type LogContext = Record<string, unknown>;
|
|
5
|
+
/**
|
|
6
|
+
* PHP: `Psr\Log\LoggerInterface`.
|
|
7
|
+
*
|
|
8
|
+
* Real Monolog implements this from the separate `psr/log` package, not from
|
|
9
|
+
* `laravel/framework`. There is no Luau port of `psr/log` to depend on
|
|
10
|
+
* instead, so the shape lives here, where the class that actually implements
|
|
11
|
+
* it lives -- `Illuminate\Contracts\Log\Logger` re-exports it rather than
|
|
12
|
+
* declaring its own copy.
|
|
13
|
+
*/
|
|
14
|
+
export interface LoggerInterface {
|
|
15
|
+
/** System is unusable. */
|
|
16
|
+
emergency(message: unknown, context?: LogContext): void;
|
|
17
|
+
/** Action must be taken immediately. */
|
|
18
|
+
alert(message: unknown, context?: LogContext): void;
|
|
19
|
+
/** Critical conditions. */
|
|
20
|
+
critical(message: unknown, context?: LogContext): void;
|
|
21
|
+
/** Runtime errors that do not require immediate action. */
|
|
22
|
+
error(message: unknown, context?: LogContext): void;
|
|
23
|
+
/** Exceptional occurrences that are not errors. */
|
|
24
|
+
warning(message: unknown, context?: LogContext): void;
|
|
25
|
+
/** Normal but significant events. */
|
|
26
|
+
notice(message: unknown, context?: LogContext): void;
|
|
27
|
+
/** Interesting events. */
|
|
28
|
+
info(message: unknown, context?: LogContext): void;
|
|
29
|
+
/** Detailed debug information. */
|
|
30
|
+
debug(message: unknown, context?: LogContext): void;
|
|
31
|
+
/** Logs with an arbitrary level. */
|
|
32
|
+
log(level: LogLevel, message: unknown, context?: LogContext): void;
|
|
33
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
--* PHP: the levels `Psr\Log\LogLevel` defines, in ascending severity.
|
|
3
|
+
--* PHP: `array $context`.
|
|
4
|
+
--[[
|
|
5
|
+
*
|
|
6
|
+
* PHP: `Psr\Log\LoggerInterface`.
|
|
7
|
+
*
|
|
8
|
+
* Real Monolog implements this from the separate `psr/log` package, not from
|
|
9
|
+
* `laravel/framework`. There is no Luau port of `psr/log` to depend on
|
|
10
|
+
* instead, so the shape lives here, where the class that actually implements
|
|
11
|
+
* it lives -- `Illuminate\Contracts\Log\Logger` re-exports it rather than
|
|
12
|
+
* declaring its own copy.
|
|
13
|
+
|
|
14
|
+
]]
|
|
15
|
+
return nil
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { LogRecord } from "../LogRecord";
|
|
2
|
+
import type { ProcessorInterface } from "./ProcessorInterface";
|
|
3
|
+
/**
|
|
4
|
+
* PHP: `Monolog\Processor\ClosureContextProcessor`.
|
|
5
|
+
*
|
|
6
|
+
* Upstream keys this off `$context[0]`, PHP's implicit first-array-index; a
|
|
7
|
+
* `RecordBag` has no positional index, so this checks whether context has
|
|
8
|
+
* exactly one entry and that entry's value is a function, regardless of its
|
|
9
|
+
* key name.
|
|
10
|
+
*/
|
|
11
|
+
export declare class ClosureContextProcessor implements ProcessorInterface {
|
|
12
|
+
process(record: LogRecord): LogRecord;
|
|
13
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
--* True when `bag` has exactly one entry; returns that entry.
|
|
3
|
+
local function soleEntry(bag)
|
|
4
|
+
local firstKey, firstValue = next(bag)
|
|
5
|
+
if firstKey == nil then
|
|
6
|
+
return nil
|
|
7
|
+
end
|
|
8
|
+
local secondKey = next(bag, firstKey)
|
|
9
|
+
if secondKey ~= nil then
|
|
10
|
+
return nil
|
|
11
|
+
end
|
|
12
|
+
return {
|
|
13
|
+
key = firstKey,
|
|
14
|
+
value = firstValue,
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
--[[
|
|
18
|
+
*
|
|
19
|
+
* PHP: `Monolog\Processor\ClosureContextProcessor`.
|
|
20
|
+
*
|
|
21
|
+
* Upstream keys this off `$context[0]`, PHP's implicit first-array-index; a
|
|
22
|
+
* `RecordBag` has no positional index, so this checks whether context has
|
|
23
|
+
* exactly one entry and that entry's value is a function, regardless of its
|
|
24
|
+
* key name.
|
|
25
|
+
|
|
26
|
+
]]
|
|
27
|
+
local ClosureContextProcessor
|
|
28
|
+
do
|
|
29
|
+
ClosureContextProcessor = setmetatable({}, {
|
|
30
|
+
__tostring = function()
|
|
31
|
+
return "ClosureContextProcessor"
|
|
32
|
+
end,
|
|
33
|
+
})
|
|
34
|
+
ClosureContextProcessor.__index = ClosureContextProcessor
|
|
35
|
+
function ClosureContextProcessor.new(...)
|
|
36
|
+
local self = setmetatable({}, ClosureContextProcessor)
|
|
37
|
+
return self:constructor(...) or self
|
|
38
|
+
end
|
|
39
|
+
function ClosureContextProcessor:constructor()
|
|
40
|
+
end
|
|
41
|
+
function ClosureContextProcessor:process(record)
|
|
42
|
+
local sole = soleEntry(record.context)
|
|
43
|
+
local _condition = sole == nil
|
|
44
|
+
if not _condition then
|
|
45
|
+
local _value = sole.value
|
|
46
|
+
_condition = not (type(_value) == "function")
|
|
47
|
+
end
|
|
48
|
+
if _condition then
|
|
49
|
+
return record
|
|
50
|
+
end
|
|
51
|
+
local ok, result = pcall(sole.value)
|
|
52
|
+
local context
|
|
53
|
+
if not ok then
|
|
54
|
+
context = {
|
|
55
|
+
error_on_context_generation = tostring(result),
|
|
56
|
+
exception = result,
|
|
57
|
+
}
|
|
58
|
+
elseif type(result) == "table" then
|
|
59
|
+
context = result
|
|
60
|
+
else
|
|
61
|
+
-- Upstream wraps a non-array result as `[$context]`, which lands back
|
|
62
|
+
-- at key `0` -- the same key it started under, since PHP's implicit
|
|
63
|
+
-- index was always `0`. Re-using the original key name here is this
|
|
64
|
+
-- port's equivalent, since there is no positional index to fall back to.
|
|
65
|
+
context = {
|
|
66
|
+
[sole.key] = result,
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
return record:with({
|
|
70
|
+
context = context,
|
|
71
|
+
})
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
return {
|
|
75
|
+
ClosureContextProcessor = ClosureContextProcessor,
|
|
76
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Level } from "../Level";
|
|
2
|
+
import type { LogLevel } from "../LoggerInterface";
|
|
3
|
+
import type { LogRecord } from "../LogRecord";
|
|
4
|
+
import type { ProcessorInterface } from "./ProcessorInterface";
|
|
5
|
+
/**
|
|
6
|
+
* PHP: `Monolog\Processor\IntrospectionProcessor`.
|
|
7
|
+
*
|
|
8
|
+
* Upstream walks `debug_backtrace()`, skipping frames belonging to
|
|
9
|
+
* `skipClassesPartials` (default `["Monolog\\"]`) and PHP's
|
|
10
|
+
* `call_user_func`/`call_user_func_array` wrappers, to find the frame that
|
|
11
|
+
* actually logged the message. Luau's `debug.info` reports one stack level at
|
|
12
|
+
* a time with no per-frame "class" the way a PHP trace frame has, so there is
|
|
13
|
+
* nothing for a class-partial skip list to match against -- `skipClassesPartials`
|
|
14
|
+
* is dropped entirely rather than faked.
|
|
15
|
+
*
|
|
16
|
+
* `BASE_STACK_OFFSET` is this port's analog of upstream's two `array_shift()`
|
|
17
|
+
* calls (its own frame, then the generic invoker frame -- `runProcessor()`
|
|
18
|
+
* here, `call_user_func` there). Unlike upstream's flat PHP call stack,
|
|
19
|
+
* `Logger.addRecord()` on this platform adds its own internal frames before
|
|
20
|
+
* reaching a processor, so the reported file/line will typically land inside
|
|
21
|
+
* that dispatch machinery rather than the original log call site. Tune
|
|
22
|
+
* `skipStackFramesCount` to compensate if more precision is needed.
|
|
23
|
+
*
|
|
24
|
+
* Warning: this only works if the handler processes the logs directly -- see
|
|
25
|
+
* upstream's own caveat, which applies here unchanged.
|
|
26
|
+
*/
|
|
27
|
+
export declare class IntrospectionProcessor implements ProcessorInterface {
|
|
28
|
+
protected skipStackFramesCount: number;
|
|
29
|
+
private static readonly BASE_STACK_OFFSET;
|
|
30
|
+
protected level: Level;
|
|
31
|
+
constructor(level?: Level | LogLevel, skipStackFramesCount?: number);
|
|
32
|
+
process(record: LogRecord): LogRecord;
|
|
33
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local _Level = TS.import(script, script.Parent.Parent, "Level")
|
|
4
|
+
local Level = _Level.Level
|
|
5
|
+
local Levels = _Level.Levels
|
|
6
|
+
local Logger = TS.import(script, script.Parent.Parent, "Logger").Logger
|
|
7
|
+
--[[
|
|
8
|
+
*
|
|
9
|
+
* PHP: `Monolog\Processor\IntrospectionProcessor`.
|
|
10
|
+
*
|
|
11
|
+
* Upstream walks `debug_backtrace()`, skipping frames belonging to
|
|
12
|
+
* `skipClassesPartials` (default `["Monolog\\"]`) and PHP's
|
|
13
|
+
* `call_user_func`/`call_user_func_array` wrappers, to find the frame that
|
|
14
|
+
* actually logged the message. Luau's `debug.info` reports one stack level at
|
|
15
|
+
* a time with no per-frame "class" the way a PHP trace frame has, so there is
|
|
16
|
+
* nothing for a class-partial skip list to match against -- `skipClassesPartials`
|
|
17
|
+
* is dropped entirely rather than faked.
|
|
18
|
+
*
|
|
19
|
+
* `BASE_STACK_OFFSET` is this port's analog of upstream's two `array_shift()`
|
|
20
|
+
* calls (its own frame, then the generic invoker frame -- `runProcessor()`
|
|
21
|
+
* here, `call_user_func` there). Unlike upstream's flat PHP call stack,
|
|
22
|
+
* `Logger.addRecord()` on this platform adds its own internal frames before
|
|
23
|
+
* reaching a processor, so the reported file/line will typically land inside
|
|
24
|
+
* that dispatch machinery rather than the original log call site. Tune
|
|
25
|
+
* `skipStackFramesCount` to compensate if more precision is needed.
|
|
26
|
+
*
|
|
27
|
+
* Warning: this only works if the handler processes the logs directly -- see
|
|
28
|
+
* upstream's own caveat, which applies here unchanged.
|
|
29
|
+
|
|
30
|
+
]]
|
|
31
|
+
local IntrospectionProcessor
|
|
32
|
+
do
|
|
33
|
+
IntrospectionProcessor = setmetatable({}, {
|
|
34
|
+
__tostring = function()
|
|
35
|
+
return "IntrospectionProcessor"
|
|
36
|
+
end,
|
|
37
|
+
})
|
|
38
|
+
IntrospectionProcessor.__index = IntrospectionProcessor
|
|
39
|
+
function IntrospectionProcessor.new(...)
|
|
40
|
+
local self = setmetatable({}, IntrospectionProcessor)
|
|
41
|
+
return self:constructor(...) or self
|
|
42
|
+
end
|
|
43
|
+
function IntrospectionProcessor:constructor(level, skipStackFramesCount)
|
|
44
|
+
if level == nil then
|
|
45
|
+
level = Level.Debug
|
|
46
|
+
end
|
|
47
|
+
if skipStackFramesCount == nil then
|
|
48
|
+
skipStackFramesCount = 0
|
|
49
|
+
end
|
|
50
|
+
self.skipStackFramesCount = skipStackFramesCount
|
|
51
|
+
self.level = Logger:toMonologLevel(level)
|
|
52
|
+
end
|
|
53
|
+
function IntrospectionProcessor:process(record)
|
|
54
|
+
if Levels:isLowerThan(record.level, self.level) then
|
|
55
|
+
return record
|
|
56
|
+
end
|
|
57
|
+
local source, line, name = debug.info(IntrospectionProcessor.BASE_STACK_OFFSET + self.skipStackFramesCount, "sln")
|
|
58
|
+
record.extra.file = source
|
|
59
|
+
record.extra.line = line
|
|
60
|
+
record.extra["function"] = name
|
|
61
|
+
-- `class`/`callType` are left unset -- Luau has no reflective notion of
|
|
62
|
+
-- "the class this call happened in" the way `$trace[$i]['class']` does.
|
|
63
|
+
return record
|
|
64
|
+
end
|
|
65
|
+
IntrospectionProcessor.BASE_STACK_OFFSET = 3
|
|
66
|
+
end
|
|
67
|
+
return {
|
|
68
|
+
IntrospectionProcessor = IntrospectionProcessor,
|
|
69
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { MemoryProcessor } from "./MemoryProcessor";
|
|
2
|
+
import type { LogRecord } from "../LogRecord";
|
|
3
|
+
/**
|
|
4
|
+
* PHP: `Monolog\Processor\MemoryPeakUsageProcessor`.
|
|
5
|
+
*
|
|
6
|
+
* There is no `memory_get_peak_usage()` equivalent -- Luau only reports
|
|
7
|
+
* *current* GC memory, not a running peak, so this tracks one itself: a
|
|
8
|
+
* private field updated to the highest reading seen so far on every call,
|
|
9
|
+
* seeded at construction. "Peak" here means the highest reading this
|
|
10
|
+
* processor instance has observed since it was created, not an OS-level
|
|
11
|
+
* peak -- a real, necessary behavioral divergence, not a cosmetic one.
|
|
12
|
+
*/
|
|
13
|
+
export declare class MemoryPeakUsageProcessor extends MemoryProcessor {
|
|
14
|
+
private peakBytes;
|
|
15
|
+
constructor(realUsage?: boolean, useFormatting?: boolean);
|
|
16
|
+
process(record: LogRecord): LogRecord;
|
|
17
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local MemoryProcessor = TS.import(script, script.Parent, "MemoryProcessor").MemoryProcessor
|
|
4
|
+
--[[
|
|
5
|
+
*
|
|
6
|
+
* PHP: `Monolog\Processor\MemoryPeakUsageProcessor`.
|
|
7
|
+
*
|
|
8
|
+
* There is no `memory_get_peak_usage()` equivalent -- Luau only reports
|
|
9
|
+
* *current* GC memory, not a running peak, so this tracks one itself: a
|
|
10
|
+
* private field updated to the highest reading seen so far on every call,
|
|
11
|
+
* seeded at construction. "Peak" here means the highest reading this
|
|
12
|
+
* processor instance has observed since it was created, not an OS-level
|
|
13
|
+
* peak -- a real, necessary behavioral divergence, not a cosmetic one.
|
|
14
|
+
|
|
15
|
+
]]
|
|
16
|
+
local MemoryPeakUsageProcessor
|
|
17
|
+
do
|
|
18
|
+
local super = MemoryProcessor
|
|
19
|
+
MemoryPeakUsageProcessor = setmetatable({}, {
|
|
20
|
+
__tostring = function()
|
|
21
|
+
return "MemoryPeakUsageProcessor"
|
|
22
|
+
end,
|
|
23
|
+
__index = super,
|
|
24
|
+
})
|
|
25
|
+
MemoryPeakUsageProcessor.__index = MemoryPeakUsageProcessor
|
|
26
|
+
function MemoryPeakUsageProcessor.new(...)
|
|
27
|
+
local self = setmetatable({}, MemoryPeakUsageProcessor)
|
|
28
|
+
return self:constructor(...) or self
|
|
29
|
+
end
|
|
30
|
+
function MemoryPeakUsageProcessor:constructor(realUsage, useFormatting)
|
|
31
|
+
if realUsage == nil then
|
|
32
|
+
realUsage = true
|
|
33
|
+
end
|
|
34
|
+
if useFormatting == nil then
|
|
35
|
+
useFormatting = true
|
|
36
|
+
end
|
|
37
|
+
super.constructor(self, realUsage, useFormatting)
|
|
38
|
+
self.peakBytes = gcinfo() * 1024
|
|
39
|
+
end
|
|
40
|
+
function MemoryPeakUsageProcessor:process(record)
|
|
41
|
+
local currentBytes = gcinfo() * 1024
|
|
42
|
+
self.peakBytes = math.max(self.peakBytes, currentBytes)
|
|
43
|
+
record.extra.memory_peak_usage = self:formatBytes(self.peakBytes)
|
|
44
|
+
return record
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
return {
|
|
48
|
+
MemoryPeakUsageProcessor = MemoryPeakUsageProcessor,
|
|
49
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { LogRecord } from "../LogRecord";
|
|
2
|
+
import type { ProcessorInterface } from "./ProcessorInterface";
|
|
3
|
+
/**
|
|
4
|
+
* PHP: `Monolog\Processor\MemoryProcessor`.
|
|
5
|
+
*
|
|
6
|
+
* `realUsage` has no real platform distinction here: `gcinfo()` (Roblox's
|
|
7
|
+
* replacement for the deprecated `collectgarbage("count")`) is the only
|
|
8
|
+
* memory reading source Luau exposes, and there is no PHP
|
|
9
|
+
* `emalloc()`-vs-OS-allocated split to choose between. The constructor
|
|
10
|
+
* parameter is kept for API-shape parity but does not change behavior in
|
|
11
|
+
* either subclass -- said once here rather than repeated in each.
|
|
12
|
+
*/
|
|
13
|
+
export declare abstract class MemoryProcessor implements ProcessorInterface {
|
|
14
|
+
protected realUsage: boolean;
|
|
15
|
+
protected useFormatting: boolean;
|
|
16
|
+
constructor(realUsage?: boolean, useFormatting?: boolean);
|
|
17
|
+
abstract process(record: LogRecord): LogRecord;
|
|
18
|
+
/** Formats bytes into a human-readable string if `useFormatting` is true, otherwise returns `bytes` as-is. */
|
|
19
|
+
protected formatBytes(bytes: number): string | number;
|
|
20
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
--[[
|
|
3
|
+
*
|
|
4
|
+
* PHP: `Monolog\Processor\MemoryProcessor`.
|
|
5
|
+
*
|
|
6
|
+
* `realUsage` has no real platform distinction here: `gcinfo()` (Roblox's
|
|
7
|
+
* replacement for the deprecated `collectgarbage("count")`) is the only
|
|
8
|
+
* memory reading source Luau exposes, and there is no PHP
|
|
9
|
+
* `emalloc()`-vs-OS-allocated split to choose between. The constructor
|
|
10
|
+
* parameter is kept for API-shape parity but does not change behavior in
|
|
11
|
+
* either subclass -- said once here rather than repeated in each.
|
|
12
|
+
|
|
13
|
+
]]
|
|
14
|
+
local MemoryProcessor
|
|
15
|
+
do
|
|
16
|
+
MemoryProcessor = {}
|
|
17
|
+
function MemoryProcessor:constructor(realUsage, useFormatting)
|
|
18
|
+
if realUsage == nil then
|
|
19
|
+
realUsage = true
|
|
20
|
+
end
|
|
21
|
+
if useFormatting == nil then
|
|
22
|
+
useFormatting = true
|
|
23
|
+
end
|
|
24
|
+
self.realUsage = realUsage
|
|
25
|
+
self.useFormatting = useFormatting
|
|
26
|
+
end
|
|
27
|
+
function MemoryProcessor:formatBytes(bytes)
|
|
28
|
+
if not self.useFormatting then
|
|
29
|
+
return bytes
|
|
30
|
+
end
|
|
31
|
+
if bytes > 1024 * 1024 then
|
|
32
|
+
return `{math.round((bytes / 1024 / 1024) * 100) / 100} MB`
|
|
33
|
+
elseif bytes > 1024 then
|
|
34
|
+
return `{math.round((bytes / 1024) * 100) / 100} KB`
|
|
35
|
+
end
|
|
36
|
+
return `{bytes} B`
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
return {
|
|
40
|
+
MemoryProcessor = MemoryProcessor,
|
|
41
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { MemoryProcessor } from "./MemoryProcessor";
|
|
2
|
+
import type { LogRecord } from "../LogRecord";
|
|
3
|
+
/**
|
|
4
|
+
* PHP: `Monolog\Processor\MemoryUsageProcessor`.
|
|
5
|
+
*
|
|
6
|
+
* `gcinfo()` (Roblox's replacement for the deprecated `collectgarbage("count")`)
|
|
7
|
+
* reports kilobytes; multiplied by 1024 so `formatBytes()` sees the same unit
|
|
8
|
+
* PHP's `memory_get_usage()` returns.
|
|
9
|
+
*/
|
|
10
|
+
export declare class MemoryUsageProcessor extends MemoryProcessor {
|
|
11
|
+
process(record: LogRecord): LogRecord;
|
|
12
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local MemoryProcessor = TS.import(script, script.Parent, "MemoryProcessor").MemoryProcessor
|
|
4
|
+
--[[
|
|
5
|
+
*
|
|
6
|
+
* PHP: `Monolog\Processor\MemoryUsageProcessor`.
|
|
7
|
+
*
|
|
8
|
+
* `gcinfo()` (Roblox's replacement for the deprecated `collectgarbage("count")`)
|
|
9
|
+
* reports kilobytes; multiplied by 1024 so `formatBytes()` sees the same unit
|
|
10
|
+
* PHP's `memory_get_usage()` returns.
|
|
11
|
+
|
|
12
|
+
]]
|
|
13
|
+
local MemoryUsageProcessor
|
|
14
|
+
do
|
|
15
|
+
local super = MemoryProcessor
|
|
16
|
+
MemoryUsageProcessor = setmetatable({}, {
|
|
17
|
+
__tostring = function()
|
|
18
|
+
return "MemoryUsageProcessor"
|
|
19
|
+
end,
|
|
20
|
+
__index = super,
|
|
21
|
+
})
|
|
22
|
+
MemoryUsageProcessor.__index = MemoryUsageProcessor
|
|
23
|
+
function MemoryUsageProcessor.new(...)
|
|
24
|
+
local self = setmetatable({}, MemoryUsageProcessor)
|
|
25
|
+
return self:constructor(...) or self
|
|
26
|
+
end
|
|
27
|
+
function MemoryUsageProcessor:constructor(...)
|
|
28
|
+
super.constructor(self, ...)
|
|
29
|
+
end
|
|
30
|
+
function MemoryUsageProcessor:process(record)
|
|
31
|
+
local usage = gcinfo() * 1024
|
|
32
|
+
record.extra.memory_usage = self:formatBytes(usage)
|
|
33
|
+
return record
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
return {
|
|
37
|
+
MemoryUsageProcessor = MemoryUsageProcessor,
|
|
38
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { LogRecord } from "../LogRecord";
|
|
2
|
+
import type { ProcessorInterface } from "./ProcessorInterface";
|
|
3
|
+
/**
|
|
4
|
+
* PHP: `Monolog\Processor\ProcessIdProcessor`.
|
|
5
|
+
*
|
|
6
|
+
* There is no OS process id on Roblox. `game.JobId` is the closest identifier
|
|
7
|
+
* for "which running process is this" -- a string, not the int
|
|
8
|
+
* `getmypid()` returns, and empty outside a real server (e.g. Studio Play
|
|
9
|
+
* testing), where it falls back to `"studio"`.
|
|
10
|
+
*/
|
|
11
|
+
export declare class ProcessIdProcessor implements ProcessorInterface {
|
|
12
|
+
process(record: LogRecord): LogRecord;
|
|
13
|
+
}
|