@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,228 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local NormalizerFormatter = TS.import(script, script.Parent, "NormalizerFormatter").NormalizerFormatter
|
|
4
|
+
--[[
|
|
5
|
+
*
|
|
6
|
+
* PHP: `Monolog\Formatter\LineFormatter`.
|
|
7
|
+
*
|
|
8
|
+
* The default format drops PHP's trailing newline -- `print` and `warn` add
|
|
9
|
+
* their own.
|
|
10
|
+
*
|
|
11
|
+
* `includeStacktraces`/`indentStacktraces`/`stacktracesParser` are kept for
|
|
12
|
+
* API-shape parity but have nothing to act on: they format PHP's
|
|
13
|
+
* `getTraceAsString()` output, and there is no PHP exception/stack-trace
|
|
14
|
+
* object on this platform for `NormalizerFormatter.normalize()` to have kept
|
|
15
|
+
* a trace from in the first place (see that file's class comment). Setting
|
|
16
|
+
* them changes bookkeeping only, never formatted output.
|
|
17
|
+
*
|
|
18
|
+
* TypeScript can't have a property and a method share a name the way PHP's
|
|
19
|
+
* `$ignoreEmptyContextAndExtra`/`ignoreEmptyContextAndExtra()` (and similarly
|
|
20
|
+
* `allowInlineLineBreaks`, `includeStacktraces`) do -- each such flag's
|
|
21
|
+
* backing field is suffixed (`...Flag`/`...Value`) below; the public method
|
|
22
|
+
* names match upstream exactly.
|
|
23
|
+
|
|
24
|
+
]]
|
|
25
|
+
local copyBag
|
|
26
|
+
local LineFormatter
|
|
27
|
+
do
|
|
28
|
+
local super = NormalizerFormatter
|
|
29
|
+
LineFormatter = setmetatable({}, {
|
|
30
|
+
__tostring = function()
|
|
31
|
+
return "LineFormatter"
|
|
32
|
+
end,
|
|
33
|
+
__index = super,
|
|
34
|
+
})
|
|
35
|
+
LineFormatter.__index = LineFormatter
|
|
36
|
+
function LineFormatter.new(...)
|
|
37
|
+
local self = setmetatable({}, LineFormatter)
|
|
38
|
+
return self:constructor(...) or self
|
|
39
|
+
end
|
|
40
|
+
function LineFormatter:constructor(format_, dateFormat, allowInlineLineBreaks, ignoreEmptyContextAndExtra, includeStacktraces)
|
|
41
|
+
if format_ == nil then
|
|
42
|
+
format_ = LineFormatter.SIMPLE_FORMAT
|
|
43
|
+
end
|
|
44
|
+
if dateFormat == nil then
|
|
45
|
+
dateFormat = LineFormatter.SIMPLE_DATE
|
|
46
|
+
end
|
|
47
|
+
if allowInlineLineBreaks == nil then
|
|
48
|
+
allowInlineLineBreaks = false
|
|
49
|
+
end
|
|
50
|
+
if ignoreEmptyContextAndExtra == nil then
|
|
51
|
+
ignoreEmptyContextAndExtra = false
|
|
52
|
+
end
|
|
53
|
+
if includeStacktraces == nil then
|
|
54
|
+
includeStacktraces = false
|
|
55
|
+
end
|
|
56
|
+
super.constructor(self, dateFormat)
|
|
57
|
+
self.format_ = format_
|
|
58
|
+
self.includeStacktracesFlag = false
|
|
59
|
+
self.indentStacktracesValue = ""
|
|
60
|
+
self.allowInlineLineBreaksFlag = allowInlineLineBreaks
|
|
61
|
+
self.ignoreEmptyContextAndExtraFlag = ignoreEmptyContextAndExtra
|
|
62
|
+
self:includeStacktraces(includeStacktraces)
|
|
63
|
+
end
|
|
64
|
+
function LineFormatter:includeStacktraces(include, parser)
|
|
65
|
+
if include == nil then
|
|
66
|
+
include = true
|
|
67
|
+
end
|
|
68
|
+
self.includeStacktracesFlag = include
|
|
69
|
+
self.stacktracesParser = parser
|
|
70
|
+
if self.includeStacktracesFlag then
|
|
71
|
+
self.allowInlineLineBreaksFlag = true
|
|
72
|
+
end
|
|
73
|
+
return self
|
|
74
|
+
end
|
|
75
|
+
function LineFormatter:indentStacktraces(indent)
|
|
76
|
+
self.indentStacktracesValue = indent
|
|
77
|
+
return self
|
|
78
|
+
end
|
|
79
|
+
function LineFormatter:allowInlineLineBreaks(allow)
|
|
80
|
+
if allow == nil then
|
|
81
|
+
allow = true
|
|
82
|
+
end
|
|
83
|
+
self.allowInlineLineBreaksFlag = allow
|
|
84
|
+
return self
|
|
85
|
+
end
|
|
86
|
+
function LineFormatter:ignoreEmptyContextAndExtra(ignore)
|
|
87
|
+
if ignore == nil then
|
|
88
|
+
ignore = true
|
|
89
|
+
end
|
|
90
|
+
self.ignoreEmptyContextAndExtraFlag = ignore
|
|
91
|
+
return self
|
|
92
|
+
end
|
|
93
|
+
function LineFormatter:setMaxLevelNameLength(maxLevelNameLength)
|
|
94
|
+
self.maxLevelNameLength = maxLevelNameLength
|
|
95
|
+
return self
|
|
96
|
+
end
|
|
97
|
+
function LineFormatter:format(record)
|
|
98
|
+
-- Upstream calls `parent::format($record)` here for the normalized
|
|
99
|
+
-- array; this port's `NormalizerFormatter.format()` returns a JSON
|
|
100
|
+
-- *string* instead (see that file's class comment), so the protected
|
|
101
|
+
-- `normalizeRecord()` is called directly instead, exactly as upstream's
|
|
102
|
+
-- own `JsonFormatter` already does.
|
|
103
|
+
local vars = self:normalizeRecord(record)
|
|
104
|
+
if self.maxLevelNameLength ~= nil then
|
|
105
|
+
local _exp = (vars.level_name)
|
|
106
|
+
local _maxLevelNameLength = self.maxLevelNameLength
|
|
107
|
+
vars.level_name = string.sub(_exp, 1, _maxLevelNameLength)
|
|
108
|
+
end
|
|
109
|
+
local output = self.format_
|
|
110
|
+
local extra = copyBag(vars.extra)
|
|
111
|
+
local context = copyBag(vars.context)
|
|
112
|
+
for key, value in pairs(extra) do
|
|
113
|
+
local placeholder = `%extra.{key}%`
|
|
114
|
+
if (string.find(output, placeholder, 1, true)) ~= nil then
|
|
115
|
+
local _exp = string.split(output, placeholder)
|
|
116
|
+
local _arg0 = self:stringify(value)
|
|
117
|
+
-- ▼ ReadonlyArray.join ▼
|
|
118
|
+
local _arg0_1 = _arg0
|
|
119
|
+
if _arg0_1 == nil then
|
|
120
|
+
_arg0_1 = ", "
|
|
121
|
+
end
|
|
122
|
+
-- ▲ ReadonlyArray.join ▲
|
|
123
|
+
output = table.concat(_exp, _arg0_1)
|
|
124
|
+
extra[key] = nil
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
for key, value in pairs(context) do
|
|
128
|
+
local placeholder = `%context.{key}%`
|
|
129
|
+
if (string.find(output, placeholder, 1, true)) ~= nil then
|
|
130
|
+
local _exp = string.split(output, placeholder)
|
|
131
|
+
local _arg0 = self:stringify(value)
|
|
132
|
+
-- ▼ ReadonlyArray.join ▼
|
|
133
|
+
local _arg0_1 = _arg0
|
|
134
|
+
if _arg0_1 == nil then
|
|
135
|
+
_arg0_1 = ", "
|
|
136
|
+
end
|
|
137
|
+
-- ▲ ReadonlyArray.join ▲
|
|
138
|
+
output = table.concat(_exp, _arg0_1)
|
|
139
|
+
context[key] = nil
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
if self.ignoreEmptyContextAndExtraFlag then
|
|
143
|
+
if (next(context)) == nil then
|
|
144
|
+
output = table.concat(string.split(output, "%context%"), "")
|
|
145
|
+
end
|
|
146
|
+
if (next(extra)) == nil then
|
|
147
|
+
output = table.concat(string.split(output, "%extra%"), "")
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
vars.context = context
|
|
151
|
+
vars.extra = extra
|
|
152
|
+
for key, value in pairs(vars) do
|
|
153
|
+
local placeholder = `%{key}%`
|
|
154
|
+
if (string.find(output, placeholder, 1, true)) ~= nil then
|
|
155
|
+
local _exp = string.split(output, placeholder)
|
|
156
|
+
local _arg0 = self:stringify(value)
|
|
157
|
+
-- ▼ ReadonlyArray.join ▼
|
|
158
|
+
local _arg0_1 = _arg0
|
|
159
|
+
if _arg0_1 == nil then
|
|
160
|
+
_arg0_1 = ", "
|
|
161
|
+
end
|
|
162
|
+
-- ▲ ReadonlyArray.join ▲
|
|
163
|
+
output = table.concat(_exp, _arg0_1)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
-- Leftover `%extra.xxx%`/`%context.xxx%` placeholders: upstream removes
|
|
167
|
+
-- them with a single PCRE alternation; Lua patterns have no `|`
|
|
168
|
+
-- alternation, so this is two passes instead of one.
|
|
169
|
+
local cleaned = string.gsub(output, "%%extra%.[^%%]-%%", "")
|
|
170
|
+
cleaned = string.gsub(cleaned, "%%context%.[^%%]-%%", "")
|
|
171
|
+
return cleaned
|
|
172
|
+
end
|
|
173
|
+
function LineFormatter:formatBatch(records)
|
|
174
|
+
local lines = {}
|
|
175
|
+
for _, record in records do
|
|
176
|
+
local _arg0 = self:format(record)
|
|
177
|
+
table.insert(lines, _arg0)
|
|
178
|
+
end
|
|
179
|
+
return table.concat(lines, "\n")
|
|
180
|
+
end
|
|
181
|
+
function LineFormatter:stringify(value)
|
|
182
|
+
return self:replaceNewlines(self:convertToString(value))
|
|
183
|
+
end
|
|
184
|
+
function LineFormatter:convertToString(data)
|
|
185
|
+
if data == nil then
|
|
186
|
+
return "null"
|
|
187
|
+
end
|
|
188
|
+
local _data = data
|
|
189
|
+
if type(_data) == "boolean" then
|
|
190
|
+
return if data then "true" else "false"
|
|
191
|
+
end
|
|
192
|
+
local _data_1 = data
|
|
193
|
+
local _condition = type(_data_1) == "string"
|
|
194
|
+
if not _condition then
|
|
195
|
+
local _data_2 = data
|
|
196
|
+
_condition = type(_data_2) == "number"
|
|
197
|
+
end
|
|
198
|
+
if _condition then
|
|
199
|
+
return tostring(data)
|
|
200
|
+
end
|
|
201
|
+
return self:toJson(data)
|
|
202
|
+
end
|
|
203
|
+
function LineFormatter:replaceNewlines(str)
|
|
204
|
+
if self.allowInlineLineBreaksFlag then
|
|
205
|
+
-- Upstream also unescapes literal `\r`/`\n` sequences inside a
|
|
206
|
+
-- JSON-looking string here via a PCRE; there is no PCRE on this
|
|
207
|
+
-- platform, so that step is dropped and the string passes through.
|
|
208
|
+
return str
|
|
209
|
+
end
|
|
210
|
+
local out = string.gsub(str, "\r\n", " ")
|
|
211
|
+
out = string.gsub(out, "\r", " ")
|
|
212
|
+
out = string.gsub(out, "\n", " ")
|
|
213
|
+
return out
|
|
214
|
+
end
|
|
215
|
+
LineFormatter.SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%"
|
|
216
|
+
LineFormatter.SIMPLE_DATE = "%Y-%m-%d %H:%M:%S"
|
|
217
|
+
end
|
|
218
|
+
--* Shallow-copy a `RecordBag` so `format()` can drop matched placeholder keys without mutating the normalized record.
|
|
219
|
+
function copyBag(bag)
|
|
220
|
+
local copy = {}
|
|
221
|
+
for key, value in pairs(bag) do
|
|
222
|
+
copy[key] = value
|
|
223
|
+
end
|
|
224
|
+
return copy
|
|
225
|
+
end
|
|
226
|
+
return {
|
|
227
|
+
LineFormatter = LineFormatter,
|
|
228
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { FormatterInterface } from "./FormatterInterface";
|
|
2
|
+
import type { LogRecord, RecordBag } from "../LogRecord";
|
|
3
|
+
/**
|
|
4
|
+
* PHP: `Monolog\Formatter\NormalizerFormatter`.
|
|
5
|
+
*
|
|
6
|
+
* Normalizes a record's context/extra into plain scalars/tables so it can be
|
|
7
|
+
* dumped to a string. Upstream's `normalize()` recognizes PHP object kinds one
|
|
8
|
+
* by one (`Throwable`, `JsonSerializable`, `__PHP_Incomplete_Class`,
|
|
9
|
+
* `is_resource`) -- none of that exists here, so anything that is not a scalar
|
|
10
|
+
* or a plain data table (a Luau table with no metatable) collapses to
|
|
11
|
+
* `tostring()`, the same way an unrecognized PHP object type would. There is
|
|
12
|
+
* no established "this is how an exception looks in a record" convention
|
|
13
|
+
* anywhere in this codebase (checked -- nothing under `src/Monolog` treats
|
|
14
|
+
* `context.exception` specially), so `normalizeException()`'s field-by-field
|
|
15
|
+
* shape (`class`/`message`/`code`/`file`/`trace`/`previous`) is not ported:
|
|
16
|
+
* there is no structured exception object to pull those fields from.
|
|
17
|
+
*
|
|
18
|
+
* `format()` is narrowed to return `string` here (this port's
|
|
19
|
+
* `FormatterInterface`, unlike upstream's `mixed`-returning one, already
|
|
20
|
+
* commits to that) rather than the raw normalized record upstream returns; it
|
|
21
|
+
* JSON-encodes `normalizeRecord()`'s result instead. Subclasses that need the
|
|
22
|
+
* raw record (`LineFormatter`, `JsonFormatter`, `ScalarFormatter`) call the
|
|
23
|
+
* protected `normalizeRecord()` directly, exactly as upstream's `JsonFormatter`
|
|
24
|
+
* already does rather than going through `parent::format()`.
|
|
25
|
+
*/
|
|
26
|
+
export declare class NormalizerFormatter implements FormatterInterface {
|
|
27
|
+
static readonly SIMPLE_DATE: string;
|
|
28
|
+
protected dateFormat: string;
|
|
29
|
+
protected maxNormalizeDepth: number;
|
|
30
|
+
protected maxNormalizeItemCount: number;
|
|
31
|
+
/** Toggled by `setJsonPrettyPrint()`; the only `jsonEncodeOptions` bit this port's encoder understands. */
|
|
32
|
+
private prettyPrint;
|
|
33
|
+
/**
|
|
34
|
+
* PHP: `NormalizerFormatter::$basePath`. Kept for API-shape parity: there
|
|
35
|
+
* is no PHP exception/stack-trace file path to shorten with it here, so
|
|
36
|
+
* it is stored and otherwise unused.
|
|
37
|
+
*/
|
|
38
|
+
protected basePath: string;
|
|
39
|
+
constructor(dateFormat?: string);
|
|
40
|
+
/** Formats a log record. */
|
|
41
|
+
format(record: LogRecord): string;
|
|
42
|
+
/** Normalize an arbitrary value to a scalar/table/undefined. */
|
|
43
|
+
normalizeValue(data: unknown): unknown;
|
|
44
|
+
/**
|
|
45
|
+
* Formats a set of log records. Upstream returns an array of normalized
|
|
46
|
+
* records (`mixed`, per its `FormatterInterface`); this JSON-encodes that
|
|
47
|
+
* same array once, for the same `string`-return reason `format()` does.
|
|
48
|
+
*/
|
|
49
|
+
formatBatch(records: Array<LogRecord>): string;
|
|
50
|
+
getDateFormat(): string;
|
|
51
|
+
setDateFormat(dateFormat: string): this;
|
|
52
|
+
/** The maximum number of normalization levels to go through. */
|
|
53
|
+
getMaxNormalizeDepth(): number;
|
|
54
|
+
setMaxNormalizeDepth(maxNormalizeDepth: number): this;
|
|
55
|
+
/** The maximum number of items to normalize per level. */
|
|
56
|
+
getMaxNormalizeItemCount(): number;
|
|
57
|
+
setMaxNormalizeItemCount(maxNormalizeItemCount: number): this;
|
|
58
|
+
/** Enables pretty-printed JSON output. */
|
|
59
|
+
setJsonPrettyPrint(enable: boolean): this;
|
|
60
|
+
/**
|
|
61
|
+
* Setting a base path would hide it from exception/stack-trace file names
|
|
62
|
+
* to shorten them upstream; there is nothing here that produces either, so
|
|
63
|
+
* this only stores the value.
|
|
64
|
+
*/
|
|
65
|
+
setBasePath(path?: string): this;
|
|
66
|
+
/**
|
|
67
|
+
* Provided as an extension point, as upstream: `normalize()` is called
|
|
68
|
+
* with sub-values of context data etc., so `normalizeRecord()` can be
|
|
69
|
+
* overridden when data needs to be appended to the record but not to other
|
|
70
|
+
* normalized data (see `JsonFormatter`).
|
|
71
|
+
*/
|
|
72
|
+
protected normalizeRecord(record: LogRecord): RecordBag;
|
|
73
|
+
protected normalize(data: unknown, depth?: number): unknown;
|
|
74
|
+
/** Return the JSON representation of a value. */
|
|
75
|
+
protected toJson(data: unknown): string;
|
|
76
|
+
protected formatDate(date: number): string;
|
|
77
|
+
/**
|
|
78
|
+
* PHP bitflag `json_encode` options have no equivalent when there is no
|
|
79
|
+
* `json_encode` to pass them to -- `toJson()` never consults this set, it
|
|
80
|
+
* exists only so callers ported against the upstream API have somewhere to
|
|
81
|
+
* put a call. Use `setJsonPrettyPrint()` for the one option this port's
|
|
82
|
+
* encoder actually understands.
|
|
83
|
+
*/
|
|
84
|
+
private jsonEncodeOptions;
|
|
85
|
+
addJsonEncodeOption(option: unknown): this;
|
|
86
|
+
removeJsonEncodeOption(option: unknown): this;
|
|
87
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local Utils = TS.import(script, script.Parent.Parent, "Utils").Utils
|
|
4
|
+
--[[
|
|
5
|
+
*
|
|
6
|
+
* PHP: `Monolog\Formatter\NormalizerFormatter`.
|
|
7
|
+
*
|
|
8
|
+
* Normalizes a record's context/extra into plain scalars/tables so it can be
|
|
9
|
+
* dumped to a string. Upstream's `normalize()` recognizes PHP object kinds one
|
|
10
|
+
* by one (`Throwable`, `JsonSerializable`, `__PHP_Incomplete_Class`,
|
|
11
|
+
* `is_resource`) -- none of that exists here, so anything that is not a scalar
|
|
12
|
+
* or a plain data table (a Luau table with no metatable) collapses to
|
|
13
|
+
* `tostring()`, the same way an unrecognized PHP object type would. There is
|
|
14
|
+
* no established "this is how an exception looks in a record" convention
|
|
15
|
+
* anywhere in this codebase (checked -- nothing under `src/Monolog` treats
|
|
16
|
+
* `context.exception` specially), so `normalizeException()`'s field-by-field
|
|
17
|
+
* shape (`class`/`message`/`code`/`file`/`trace`/`previous`) is not ported:
|
|
18
|
+
* there is no structured exception object to pull those fields from.
|
|
19
|
+
*
|
|
20
|
+
* `format()` is narrowed to return `string` here (this port's
|
|
21
|
+
* `FormatterInterface`, unlike upstream's `mixed`-returning one, already
|
|
22
|
+
* commits to that) rather than the raw normalized record upstream returns; it
|
|
23
|
+
* JSON-encodes `normalizeRecord()`'s result instead. Subclasses that need the
|
|
24
|
+
* raw record (`LineFormatter`, `JsonFormatter`, `ScalarFormatter`) call the
|
|
25
|
+
* protected `normalizeRecord()` directly, exactly as upstream's `JsonFormatter`
|
|
26
|
+
* already does rather than going through `parent::format()`.
|
|
27
|
+
|
|
28
|
+
]]
|
|
29
|
+
local NormalizerFormatter
|
|
30
|
+
do
|
|
31
|
+
NormalizerFormatter = setmetatable({}, {
|
|
32
|
+
__tostring = function()
|
|
33
|
+
return "NormalizerFormatter"
|
|
34
|
+
end,
|
|
35
|
+
})
|
|
36
|
+
NormalizerFormatter.__index = NormalizerFormatter
|
|
37
|
+
function NormalizerFormatter.new(...)
|
|
38
|
+
local self = setmetatable({}, NormalizerFormatter)
|
|
39
|
+
return self:constructor(...) or self
|
|
40
|
+
end
|
|
41
|
+
function NormalizerFormatter:constructor(dateFormat)
|
|
42
|
+
self.maxNormalizeDepth = 9
|
|
43
|
+
self.maxNormalizeItemCount = 1000
|
|
44
|
+
self.prettyPrint = false
|
|
45
|
+
self.basePath = ""
|
|
46
|
+
self.jsonEncodeOptions = {}
|
|
47
|
+
local _condition = dateFormat
|
|
48
|
+
if _condition == nil then
|
|
49
|
+
_condition = NormalizerFormatter.SIMPLE_DATE
|
|
50
|
+
end
|
|
51
|
+
self.dateFormat = _condition
|
|
52
|
+
end
|
|
53
|
+
function NormalizerFormatter:format(record)
|
|
54
|
+
return self:toJson(self:normalizeRecord(record))
|
|
55
|
+
end
|
|
56
|
+
function NormalizerFormatter:normalizeValue(data)
|
|
57
|
+
return self:normalize(data)
|
|
58
|
+
end
|
|
59
|
+
function NormalizerFormatter:formatBatch(records)
|
|
60
|
+
local normalized = {}
|
|
61
|
+
for _, record in records do
|
|
62
|
+
local _arg0 = self:normalizeRecord(record)
|
|
63
|
+
table.insert(normalized, _arg0)
|
|
64
|
+
end
|
|
65
|
+
return self:toJson(normalized)
|
|
66
|
+
end
|
|
67
|
+
function NormalizerFormatter:getDateFormat()
|
|
68
|
+
return self.dateFormat
|
|
69
|
+
end
|
|
70
|
+
function NormalizerFormatter:setDateFormat(dateFormat)
|
|
71
|
+
self.dateFormat = dateFormat
|
|
72
|
+
return self
|
|
73
|
+
end
|
|
74
|
+
function NormalizerFormatter:getMaxNormalizeDepth()
|
|
75
|
+
return self.maxNormalizeDepth
|
|
76
|
+
end
|
|
77
|
+
function NormalizerFormatter:setMaxNormalizeDepth(maxNormalizeDepth)
|
|
78
|
+
self.maxNormalizeDepth = maxNormalizeDepth
|
|
79
|
+
return self
|
|
80
|
+
end
|
|
81
|
+
function NormalizerFormatter:getMaxNormalizeItemCount()
|
|
82
|
+
return self.maxNormalizeItemCount
|
|
83
|
+
end
|
|
84
|
+
function NormalizerFormatter:setMaxNormalizeItemCount(maxNormalizeItemCount)
|
|
85
|
+
self.maxNormalizeItemCount = maxNormalizeItemCount
|
|
86
|
+
return self
|
|
87
|
+
end
|
|
88
|
+
function NormalizerFormatter:setJsonPrettyPrint(enable)
|
|
89
|
+
self.prettyPrint = enable
|
|
90
|
+
return self
|
|
91
|
+
end
|
|
92
|
+
function NormalizerFormatter:setBasePath(path)
|
|
93
|
+
if path == nil then
|
|
94
|
+
path = ""
|
|
95
|
+
end
|
|
96
|
+
self.basePath = path
|
|
97
|
+
return self
|
|
98
|
+
end
|
|
99
|
+
function NormalizerFormatter:normalizeRecord(record)
|
|
100
|
+
local normalized = self:normalize(record:toArray())
|
|
101
|
+
-- `datetime` is a plain Unix timestamp, not a `DateTimeInterface`
|
|
102
|
+
-- upstream's `normalize()` can recognize among arbitrary values by type
|
|
103
|
+
-- -- there is nothing to `instanceof`-check here, so it is formatted
|
|
104
|
+
-- explicitly instead of relying on that recursive detection.
|
|
105
|
+
normalized.datetime = self:formatDate(record.datetime)
|
|
106
|
+
return normalized
|
|
107
|
+
end
|
|
108
|
+
function NormalizerFormatter:normalize(data, depth)
|
|
109
|
+
if depth == nil then
|
|
110
|
+
depth = 0
|
|
111
|
+
end
|
|
112
|
+
if depth > self.maxNormalizeDepth then
|
|
113
|
+
return `Over {self.maxNormalizeDepth} levels deep, aborting normalization`
|
|
114
|
+
end
|
|
115
|
+
if data == nil then
|
|
116
|
+
return nil
|
|
117
|
+
end
|
|
118
|
+
local _data = data
|
|
119
|
+
local _condition = type(_data) == "string"
|
|
120
|
+
if not _condition then
|
|
121
|
+
local _data_1 = data
|
|
122
|
+
_condition = type(_data_1) == "boolean"
|
|
123
|
+
end
|
|
124
|
+
if _condition then
|
|
125
|
+
return data
|
|
126
|
+
end
|
|
127
|
+
local _data_1 = data
|
|
128
|
+
if type(_data_1) == "number" then
|
|
129
|
+
if data ~= data then
|
|
130
|
+
return "NaN"
|
|
131
|
+
end
|
|
132
|
+
if data == math.huge then
|
|
133
|
+
return "INF"
|
|
134
|
+
end
|
|
135
|
+
if data == -math.huge then
|
|
136
|
+
return "-INF"
|
|
137
|
+
end
|
|
138
|
+
return data
|
|
139
|
+
end
|
|
140
|
+
local _data_2 = data
|
|
141
|
+
if type(_data_2) == "table" then
|
|
142
|
+
-- A table with a metatable is a class instance (a Roblox `Instance`,
|
|
143
|
+
-- an OOP object elsewhere in this codebase, etc.) rather than plain
|
|
144
|
+
-- record data -- there is no PHP object/`Throwable`/`JsonSerializable`
|
|
145
|
+
-- system to special-case one against, so it collapses to a string the
|
|
146
|
+
-- same way an unrecognized PHP object type would.
|
|
147
|
+
if getmetatable(data) ~= nil then
|
|
148
|
+
return tostring(data)
|
|
149
|
+
end
|
|
150
|
+
local list = data
|
|
151
|
+
if #list > 0 then
|
|
152
|
+
-- `Array<T>.push()` requires `T extends defined` (Luau arrays
|
|
153
|
+
-- cannot reliably hold a `nil` mid-list); a normalized value is
|
|
154
|
+
-- rarely actually `undefined`, but cast rather than narrow the
|
|
155
|
+
-- element type to `unknown`, which `push()` itself rejects.
|
|
156
|
+
local normalized = {}
|
|
157
|
+
local count = 0
|
|
158
|
+
for _, item in list do
|
|
159
|
+
count += 1
|
|
160
|
+
if count > self.maxNormalizeItemCount then
|
|
161
|
+
local _arg0 = `Over {self.maxNormalizeItemCount} items ({#list} total), aborting normalization`
|
|
162
|
+
table.insert(normalized, _arg0)
|
|
163
|
+
break
|
|
164
|
+
end
|
|
165
|
+
local _arg0 = self:normalize(item, depth + 1)
|
|
166
|
+
table.insert(normalized, _arg0)
|
|
167
|
+
end
|
|
168
|
+
return normalized
|
|
169
|
+
end
|
|
170
|
+
local bag = data
|
|
171
|
+
local keys = {}
|
|
172
|
+
for key in pairs(bag) do
|
|
173
|
+
local _arg0 = tostring(key)
|
|
174
|
+
table.insert(keys, _arg0)
|
|
175
|
+
end
|
|
176
|
+
table.sort(keys)
|
|
177
|
+
local normalized = {}
|
|
178
|
+
local count = 0
|
|
179
|
+
for _, key in keys do
|
|
180
|
+
count += 1
|
|
181
|
+
if count > self.maxNormalizeItemCount then
|
|
182
|
+
normalized["..."] = `Over {self.maxNormalizeItemCount} items ({#keys} total), aborting normalization`
|
|
183
|
+
break
|
|
184
|
+
end
|
|
185
|
+
normalized[key] = self:normalize(bag[key], depth + 1)
|
|
186
|
+
end
|
|
187
|
+
return normalized
|
|
188
|
+
end
|
|
189
|
+
-- Function/thread/opaque instance: nothing left to reflect on.
|
|
190
|
+
return tostring(data)
|
|
191
|
+
end
|
|
192
|
+
function NormalizerFormatter:toJson(data)
|
|
193
|
+
return Utils:jsonEncode(data, self.prettyPrint)
|
|
194
|
+
end
|
|
195
|
+
function NormalizerFormatter:formatDate(date)
|
|
196
|
+
return os.date(self.dateFormat, date)
|
|
197
|
+
end
|
|
198
|
+
function NormalizerFormatter:addJsonEncodeOption(option)
|
|
199
|
+
local _jsonEncodeOptions = self.jsonEncodeOptions
|
|
200
|
+
local _option = option
|
|
201
|
+
_jsonEncodeOptions[_option] = true
|
|
202
|
+
return self
|
|
203
|
+
end
|
|
204
|
+
function NormalizerFormatter:removeJsonEncodeOption(option)
|
|
205
|
+
local _jsonEncodeOptions = self.jsonEncodeOptions
|
|
206
|
+
local _option = option
|
|
207
|
+
_jsonEncodeOptions[_option] = nil
|
|
208
|
+
return self
|
|
209
|
+
end
|
|
210
|
+
NormalizerFormatter.SIMPLE_DATE = "%Y-%m-%dT%H:%M:%S%z"
|
|
211
|
+
end
|
|
212
|
+
return {
|
|
213
|
+
NormalizerFormatter = NormalizerFormatter,
|
|
214
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { NormalizerFormatter } from "./NormalizerFormatter";
|
|
2
|
+
import type { LogRecord, RecordBag } from "../LogRecord";
|
|
3
|
+
/**
|
|
4
|
+
* PHP: `Monolog\Formatter\ScalarFormatter`.
|
|
5
|
+
*
|
|
6
|
+
* Formats data into a map of scalar (or `undefined`) values; anything
|
|
7
|
+
* non-scalar is JSON-encoded instead. Upstream's `format()` returns that map
|
|
8
|
+
* directly; this port's `FormatterInterface.format()` is narrowed to `string`
|
|
9
|
+
* (see `NormalizerFormatter`'s class comment), so `format()` here JSON-encodes
|
|
10
|
+
* it, and the map itself is exposed as `toScalarRecord()` for callers that
|
|
11
|
+
* want the structured form.
|
|
12
|
+
*/
|
|
13
|
+
export declare class ScalarFormatter extends NormalizerFormatter {
|
|
14
|
+
/** Formats a log record. */
|
|
15
|
+
format(record: LogRecord): string;
|
|
16
|
+
/** PHP: `ScalarFormatter::format()`'s actual return value. */
|
|
17
|
+
toScalarRecord(record: LogRecord): RecordBag;
|
|
18
|
+
protected toScalar(value: unknown): unknown;
|
|
19
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local NormalizerFormatter = TS.import(script, script.Parent, "NormalizerFormatter").NormalizerFormatter
|
|
4
|
+
--[[
|
|
5
|
+
*
|
|
6
|
+
* PHP: `Monolog\Formatter\ScalarFormatter`.
|
|
7
|
+
*
|
|
8
|
+
* Formats data into a map of scalar (or `undefined`) values; anything
|
|
9
|
+
* non-scalar is JSON-encoded instead. Upstream's `format()` returns that map
|
|
10
|
+
* directly; this port's `FormatterInterface.format()` is narrowed to `string`
|
|
11
|
+
* (see `NormalizerFormatter`'s class comment), so `format()` here JSON-encodes
|
|
12
|
+
* it, and the map itself is exposed as `toScalarRecord()` for callers that
|
|
13
|
+
* want the structured form.
|
|
14
|
+
|
|
15
|
+
]]
|
|
16
|
+
local ScalarFormatter
|
|
17
|
+
do
|
|
18
|
+
local super = NormalizerFormatter
|
|
19
|
+
ScalarFormatter = setmetatable({}, {
|
|
20
|
+
__tostring = function()
|
|
21
|
+
return "ScalarFormatter"
|
|
22
|
+
end,
|
|
23
|
+
__index = super,
|
|
24
|
+
})
|
|
25
|
+
ScalarFormatter.__index = ScalarFormatter
|
|
26
|
+
function ScalarFormatter.new(...)
|
|
27
|
+
local self = setmetatable({}, ScalarFormatter)
|
|
28
|
+
return self:constructor(...) or self
|
|
29
|
+
end
|
|
30
|
+
function ScalarFormatter:constructor(...)
|
|
31
|
+
super.constructor(self, ...)
|
|
32
|
+
end
|
|
33
|
+
function ScalarFormatter:format(record)
|
|
34
|
+
return self:toJson(self:toScalarRecord(record))
|
|
35
|
+
end
|
|
36
|
+
function ScalarFormatter:toScalarRecord(record)
|
|
37
|
+
local result = {}
|
|
38
|
+
for key, value in pairs(record:toArray()) do
|
|
39
|
+
result[key] = self:toScalar(value)
|
|
40
|
+
end
|
|
41
|
+
return result
|
|
42
|
+
end
|
|
43
|
+
function ScalarFormatter:toScalar(value)
|
|
44
|
+
local normalized = self:normalize(value)
|
|
45
|
+
if type(normalized) == "table" then
|
|
46
|
+
return self:toJson(normalized)
|
|
47
|
+
end
|
|
48
|
+
return normalized
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
return {
|
|
52
|
+
ScalarFormatter = ScalarFormatter,
|
|
53
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Handler } from "./Handler";
|
|
2
|
+
import { Level } from "../Level";
|
|
3
|
+
import type { LogRecord } from "../LogRecord";
|
|
4
|
+
import type { ResettableInterface } from "../ResettableInterface";
|
|
5
|
+
/** PHP: `Monolog\Handler\AbstractHandler`. */
|
|
6
|
+
export declare abstract class AbstractHandler extends Handler implements ResettableInterface {
|
|
7
|
+
protected level: Level;
|
|
8
|
+
protected bubble: boolean;
|
|
9
|
+
constructor(level?: Level, bubble?: boolean);
|
|
10
|
+
/** Checks whether the given record will be handled by this handler. */
|
|
11
|
+
isHandling(record: LogRecord): boolean;
|
|
12
|
+
/** Sets minimum logging level at which this handler will be triggered. */
|
|
13
|
+
setLevel(level: Level): this;
|
|
14
|
+
/** Gets minimum logging level at which this handler will be triggered. */
|
|
15
|
+
getLevel(): Level;
|
|
16
|
+
/** Sets the bubbling behavior. */
|
|
17
|
+
setBubble(bubble: boolean): this;
|
|
18
|
+
/** Gets the bubbling behavior. */
|
|
19
|
+
getBubble(): boolean;
|
|
20
|
+
/** Resets the handler's state. */
|
|
21
|
+
reset(): void;
|
|
22
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local Handler = TS.import(script, script.Parent, "Handler").Handler
|
|
4
|
+
local Level = TS.import(script, script.Parent.Parent, "Level").Level
|
|
5
|
+
--* PHP: `Monolog\Handler\AbstractHandler`.
|
|
6
|
+
local AbstractHandler
|
|
7
|
+
do
|
|
8
|
+
local super = Handler
|
|
9
|
+
AbstractHandler = setmetatable({}, {
|
|
10
|
+
__tostring = function()
|
|
11
|
+
return "AbstractHandler"
|
|
12
|
+
end,
|
|
13
|
+
__index = super,
|
|
14
|
+
})
|
|
15
|
+
AbstractHandler.__index = AbstractHandler
|
|
16
|
+
function AbstractHandler:constructor(level, bubble)
|
|
17
|
+
if level == nil then
|
|
18
|
+
level = Level.Debug
|
|
19
|
+
end
|
|
20
|
+
if bubble == nil then
|
|
21
|
+
bubble = true
|
|
22
|
+
end
|
|
23
|
+
super.constructor(self)
|
|
24
|
+
self.level = level
|
|
25
|
+
self.bubble = bubble
|
|
26
|
+
end
|
|
27
|
+
function AbstractHandler:isHandling(record)
|
|
28
|
+
return record.level >= self.level
|
|
29
|
+
end
|
|
30
|
+
function AbstractHandler:setLevel(level)
|
|
31
|
+
self.level = level
|
|
32
|
+
return self
|
|
33
|
+
end
|
|
34
|
+
function AbstractHandler:getLevel()
|
|
35
|
+
return self.level
|
|
36
|
+
end
|
|
37
|
+
function AbstractHandler:setBubble(bubble)
|
|
38
|
+
self.bubble = bubble
|
|
39
|
+
return self
|
|
40
|
+
end
|
|
41
|
+
function AbstractHandler:getBubble()
|
|
42
|
+
return self.bubble
|
|
43
|
+
end
|
|
44
|
+
function AbstractHandler:reset()
|
|
45
|
+
--
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
return {
|
|
49
|
+
AbstractHandler = AbstractHandler,
|
|
50
|
+
}
|