line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
MODE: INLINE |
2
|
|
|
|
|
|
|
#include "util.h" |
3
|
|
|
|
|
|
|
using namespace xs::xlog; |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
namespace { |
6
|
|
|
|
|
|
|
static bool no_format_warnings; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
struct PerlObjectFormatter : IFormatter, Backref { |
9
|
|
|
|
|
|
|
string format (std::string& msg, const Info& i) const override { |
10
|
|
|
|
|
|
|
if (!is_perl_thread()) throw std::logic_error("can't call pure-perl formatting callback: log() called from perl-foreign thread"); |
11
|
|
|
|
|
|
|
Object o = xs::out(this); |
12
|
|
|
|
|
|
|
auto ret = o.call("format", xs::out(msg), xs::out(i.level), xs::out(i.module->name()), xs::out(i.file), xs::out(i.line), xs::out(i.func)); |
13
|
|
|
|
|
|
|
return xs::in(ret); |
14
|
|
|
|
|
|
|
} |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
~PerlObjectFormatter () { Backref::dtor(); } |
17
|
|
|
|
|
|
|
}; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
struct PerlObjectLogger : ILogger, Backref { |
20
|
|
|
|
|
|
|
void log_format (std::string& msg, const Info& i, const IFormatter& fmt) override { |
21
|
|
|
|
|
|
|
if (!is_perl_thread()) throw std::logic_error("can't call pure-perl logging callback: log() called from perl-foreign thread"); |
22
|
|
|
|
|
|
|
Object o = xs::out(this); |
23
|
|
|
|
|
|
|
auto sub = o.method("log_format"); |
24
|
|
|
|
|
|
|
if (!sub) return ILogger::log_format(msg, i, fmt); |
25
|
|
|
|
|
|
|
sub.call(o.ref(), xs::out(msg), xs::out(i.level), xs::out(i.module->name()), xs::out(i.file), xs::out(i.line), xs::out(i.func), xs::out(&fmt)); |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
void log (const string& msg, const Info& info) override { |
29
|
|
|
|
|
|
|
if (!is_perl_thread()) throw std::logic_error("can't call pure-perl logging callback: log() called from perl-foreign thread"); |
30
|
|
|
|
|
|
|
Object o = xs::out(this); |
31
|
|
|
|
|
|
|
o.call("log", xs::out(msg), xs::out(info.level)); |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
~PerlObjectLogger () { Backref::dtor(); } |
35
|
|
|
|
|
|
|
}; |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
struct NoWarningsGuard { |
38
|
|
|
|
|
|
|
NoWarningsGuard (bool enabled) : _enabled(enabled), _cop_warnings(), _dowarn() { |
39
|
|
|
|
|
|
|
if (!_enabled) return; |
40
|
|
|
|
|
|
|
_cop_warnings = PL_curcop->cop_warnings; |
41
|
|
|
|
|
|
|
_dowarn = PL_dowarn; |
42
|
|
|
|
|
|
|
PL_curcop->cop_warnings = pWARN_STD; |
43
|
|
|
|
|
|
|
PL_dowarn &= ~G_WARN_ON; |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
~NoWarningsGuard () { |
47
|
|
|
|
|
|
|
if (!_enabled) return; |
48
|
|
|
|
|
|
|
PL_curcop->cop_warnings = _cop_warnings; |
49
|
|
|
|
|
|
|
PL_dowarn = _dowarn; |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
private: |
53
|
|
|
|
|
|
|
bool _enabled; |
54
|
|
|
|
|
|
|
decltype(PL_curcop->cop_warnings) _cop_warnings; |
55
|
|
|
|
|
|
|
U8 _dowarn; |
56
|
|
|
|
|
|
|
}; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
namespace xs { |
60
|
|
|
|
|
|
|
template struct Typemap : Typemap {}; |
61
|
|
|
|
|
|
|
template struct Typemap : Typemap {}; |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
#undef PANDA_LOG_CODE_POINT |
65
|
|
|
|
|
|
|
#define PANDA_LOG_CODE_POINT make_code_point() |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
static inline CV* get_context_sub () { |
68
|
|
|
|
|
|
|
int depth = 0; |
69
|
|
|
|
|
|
|
auto ctx = caller_cx(depth, nullptr); |
70
|
|
|
|
|
|
|
while (ctx) { |
71
|
|
|
|
|
|
|
if (CxTYPE(ctx) == CXt_SUB) return ctx->blk_sub.cv; |
72
|
|
|
|
|
|
|
ctx = caller_cx(++depth, nullptr); |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
return nullptr; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
static inline CodePoint make_code_point () { |
78
|
|
|
|
|
|
|
auto cop = PL_curcop; |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
string_view func; |
81
|
|
|
|
|
|
|
auto cv = get_context_sub(); |
82
|
|
|
|
|
|
|
if (cv) { |
83
|
|
|
|
|
|
|
GV* gv = CvGV(cv); |
84
|
|
|
|
|
|
|
if (gv) func = string_view(GvNAME(gv), GvNAMELEN(gv)); |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
return CodePoint{CopFILE(cop), CopLINE(cop), func}; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
static inline Sv format_args (SV** args, int items) { |
91
|
|
|
|
|
|
|
if (!items) return Simple(default_message); |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
if (items == 1) { |
94
|
|
|
|
|
|
|
Sv arg(args[0]); |
95
|
|
|
|
|
|
|
if (arg.is_simple()) { return arg; } |
96
|
|
|
|
|
|
|
else { return Simple(SvPV_nolen(args[0])); } |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
NoWarningsGuard g(no_format_warnings); (void)g; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
STRLEN patlen; |
102
|
|
|
|
|
|
|
auto pat = SvPV(args[0], patlen); |
103
|
|
|
|
|
|
|
Sv ret = Simple::create(patlen * 1.5); |
104
|
|
|
|
|
|
|
bool stub = false; |
105
|
|
|
|
|
|
|
sv_vcatpvfn(ret, pat, patlen, nullptr, args + 1, items - 1, &stub); |
106
|
|
|
|
|
|
|
return ret; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
static inline void peep_args (SV**& args, I32& items, const Module*& module, Sub& sub) { |
110
|
|
|
|
|
|
|
if (items && SvROK(args[0])) { |
111
|
|
|
|
|
|
|
auto first = SvRV(args[0]); |
112
|
|
|
|
|
|
|
if (has_module(first)) { |
113
|
|
|
|
|
|
|
module = xs::in(first); |
114
|
|
|
|
|
|
|
++args; |
115
|
|
|
|
|
|
|
--items; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
else if (SvTYPE(first) == SVt_PVCV) { |
118
|
|
|
|
|
|
|
if (items > 1) throw exception("no arguments should follow subref when logging"); |
119
|
|
|
|
|
|
|
sub = first; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
if (!module) module = resolve_module(0); // auto detect module by namespace |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
template |
127
|
|
|
|
|
|
|
void forward(Log&& log, SV**& args, I32& items, Sub& sub) { |
128
|
|
|
|
|
|
|
Simple msg; |
129
|
|
|
|
|
|
|
if (sub) { |
130
|
|
|
|
|
|
|
Sv ret = sub.call(); |
131
|
|
|
|
|
|
|
SV* sv = ret; |
132
|
|
|
|
|
|
|
msg = format_args(&sv, 1); |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
else { |
135
|
|
|
|
|
|
|
msg = format_args(args, items); |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
log << msg.as_string(); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
static void xslog (Level level, SV** args, I32 items) { |
141
|
|
|
|
|
|
|
const Module* module = nullptr; |
142
|
|
|
|
|
|
|
Sub sub; |
143
|
|
|
|
|
|
|
peep_args(args, items, module, sub); |
144
|
|
|
|
|
|
|
panda_log(level, *module, [&]{ forward(log, args, items, sub); }); |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
MODULE = XLog PACKAGE = XLog |
148
|
|
|
|
|
|
|
PROTOTYPES: DISABLE |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
BOOT { |
151
|
16
|
50
|
|
|
|
|
Stash stash(__PACKAGE__); |
152
|
|
|
|
|
|
|
|
153
|
88
|
50
|
|
|
|
|
xs::exp::create_constants(stash, { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
154
|
|
|
|
|
|
|
{"VERBOSE_DEBUG", (int)Level::VerboseDebug}, |
155
|
|
|
|
|
|
|
{"DEBUG", (int)Level::Debug}, |
156
|
|
|
|
|
|
|
{"INFO", (int)Level::Info}, |
157
|
|
|
|
|
|
|
{"NOTICE", (int)Level::Notice}, |
158
|
|
|
|
|
|
|
{"WARNING", (int)Level::Warning}, |
159
|
|
|
|
|
|
|
{"ERROR", (int)Level::Error}, |
160
|
|
|
|
|
|
|
{"CRITICAL", (int)Level::Critical}, |
161
|
|
|
|
|
|
|
{"ALERT", (int)Level::Alert}, |
162
|
|
|
|
|
|
|
{"EMERGENCY", (int)Level::Emergency}, |
163
|
80
|
50
|
|
|
|
|
}); |
164
|
|
|
|
|
|
|
|
165
|
16
|
50
|
|
|
|
|
auto root_module = xs::out(&::panda_log_module); |
166
|
8
|
|
|
|
|
|
root_module.readonly(1); |
167
|
8
|
50
|
|
|
|
|
stash.add_const_sub("default_format", xs::out(default_format)); |
|
|
50
|
|
|
|
|
|
168
|
8
|
50
|
|
|
|
|
stash.add_const_sub("root", root_module); |
169
|
8
|
50
|
|
|
|
|
stash.store("root_module", root_module); |
170
|
|
|
|
|
|
|
|
171
|
32
|
50
|
|
|
|
|
xs::at_perl_destroy([]{ |
172
|
8
|
50
|
|
|
|
|
if (dyn_cast(get_logger().get())) set_logger(nullptr); |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
173
|
8
|
50
|
|
|
|
|
if (dyn_cast(get_formatter().get())) set_formatter(nullptr); |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
174
|
24
|
50
|
|
|
|
|
}); |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
31
|
50
|
|
|
|
|
void set_level (Level level, string_view module = {}) |
178
|
|
|
|
|
|
|
|
179
|
55
|
50
|
|
|
|
|
void set_logger (ILoggerSP logger) |
|
|
50
|
|
|
|
|
|
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
void set_formatter (IFormatterSP fmt) : ALIAS(set_format=1) { |
182
|
|
|
|
|
|
|
(void)ix; |
183
|
52
|
50
|
|
|
|
|
set_formatter(fmt); |
|
|
50
|
|
|
|
|
|
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
2
|
|
|
|
|
|
ILoggerSP get_logger () |
187
|
1
|
50
|
|
|
|
|
|
188
|
2
|
|
|
|
|
|
IFormatterSP get_formatter () |
189
|
1
|
50
|
|
|
|
|
|
190
|
6
|
|
|
|
|
|
Module* get_module (string_view name) |
191
|
3
|
50
|
|
|
|
|
|
192
|
|
|
|
|
|
|
void log (Level level, ...) { |
193
|
64
|
|
|
|
|
|
xslog(level, &ST(1), items-1); |
194
|
64
|
100
|
|
|
|
|
if (!(PL_op->op_spare & 1)) xlog::optimize(); |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Module* resolve_module (size_t depth = 0) { |
198
|
40
|
|
|
|
|
|
RETVAL = resolve_module(depth); |
199
|
20
|
50
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
void disable_format_warnings () : ALIAS(enable_format_warnings=1) { |
202
|
2
|
|
|
|
|
|
no_format_warnings = !ix; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
void __logXXX (...) : ALIAS(verbose_debug=0, debug=1, info=2, notice=3, warning=4, error=5, critical=6, alert=7, emergency=8) { |
206
|
104
|
|
|
|
|
|
Level level = Level((int)Level::VerboseDebug + ix); |
207
|
104
|
|
|
|
|
|
xslog(level, &ST(0), items); |
208
|
102
|
100
|
|
|
|
|
if (!(PL_op->op_spare & 1)) xlog::optimize(level); |
209
|
|
|
|
|
|
|
} |