File Coverage

xs/XLog.xsi
Criterion Covered Total %
statement 28 28 100.0
branch 38 76 50.0
condition n/a
subroutine n/a
pod n/a
total 66 104 63.4


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             }