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