82c8ba | 2015-08-12 | Marcus Agehall | |
|
f9ef9f | 2015-10-16 | Marcus Agehall | | class BaseJSONLogger {
constant BUNYAN_VERSION = 0;
|
82c8ba | 2015-08-12 | Marcus Agehall | | object parent_logger;
|
f9ef9f | 2015-10-16 | Marcus Agehall | | string logger_name = "unknown";
string hostname = (functionp(System.gethostname) && System.gethostname()) || "unknown";
int pid = System.getpid();
mapping|function defaults = ([
|
82c8ba | 2015-08-12 | Marcus Agehall | | "level" : INFO,
]);
enum {
TRACE = 10,
|
63479a | 2015-10-15 | Jonas Walldén | | DBG = 20,
|
82c8ba | 2015-08-12 | Marcus Agehall | | INFO = 30,
WARN = 40,
ERROR = 50,
FATAL = 60
};
int default_log_level = INFO;
|
75cb5c | 2015-10-16 | Marcus Agehall | | int drop_messages_below = 0;
|
82c8ba | 2015-08-12 | Marcus Agehall | |
|
75cb5c | 2015-10-16 | Marcus Agehall | | int should_log(string|mapping msg) {
int level = (stringp(msg) && default_log_level) || msg->level || default_log_level;
if (level < drop_messages_below) return 0;
|
82c8ba | 2015-08-12 | Marcus Agehall | | if (parent_logger)
|
75cb5c | 2015-10-16 | Marcus Agehall | | return parent_logger->should_log(msg);
|
82c8ba | 2015-08-12 | Marcus Agehall | |
return 1;
}
protected void do_log(mapping data) {
if (!data->level) {
data = data | ([]);
data->level = default_log_level;
}
string res = Standards.JSON.encode(data);
}
|
f9ef9f | 2015-10-16 | Marcus Agehall | |
string get_bunyan_timestamp() {
array(int) tod = System.gettimeofday();
mapping gt = gmtime(tod[0]);
string ret = sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ",
1900 + gt->year, 1+gt->mon, gt->mday,
gt->hour, gt->min, gt->sec,
tod[1]/1000);
return ret;
}
|
82c8ba | 2015-08-12 | Marcus Agehall | |
protected mapping merge_defaults(mapping msg) {
|
f9ef9f | 2015-10-16 | Marcus Agehall | | mapping ret = ((functionp(defaults) && defaults()) || defaults) | msg;
ret->v = BUNYAN_VERSION;
ret->name = ret->name || logger_name;
ret->hostname = hostname;
ret->pid = pid;
ret->time = get_bunyan_timestamp();
ret->msg = ret->msg || "";
return ret;
|
82c8ba | 2015-08-12 | Marcus Agehall | | }
void log(mapping|string data) {
|
75cb5c | 2015-10-16 | Marcus Agehall | | if (!should_log(data)) {
|
82c8ba | 2015-08-12 | Marcus Agehall | | return;
}
if (stringp(data)) {
data = ([ "msg" : data ]);
}
mapping log_entry = merge_defaults(data);
if (parent_logger && functionp(parent_logger->log)) {
parent_logger->log(log_entry);
} else {
do_log(log_entry);
}
}
|
f9ef9f | 2015-10-16 | Marcus Agehall | | void set_name(void|string name) {
logger_name = name || "unknown";
}
void set_defaults(void|function|mapping new_defaults) {
defaults = new_defaults || ([]);
}
|
82c8ba | 2015-08-12 | Marcus Agehall | |
|
f9ef9f | 2015-10-16 | Marcus Agehall | | void create(void|string logger_name, void|mapping|function defaults, void|object parent_logger) {
set_defaults(defaults);
|
82c8ba | 2015-08-12 | Marcus Agehall | | this_program::parent_logger = parent_logger;
|
f9ef9f | 2015-10-16 | Marcus Agehall | | set_name(logger_name);
|
82c8ba | 2015-08-12 | Marcus Agehall | | }
|
75cb5c | 2015-10-16 | Marcus Agehall | | this_program child(string logger_name, void|mapping|function defaults) {
logger_name = combine_path_unix(this_program::logger_name, logger_name);
this_program new_logger = object_program(this)(logger_name, defaults, this);
|
82c8ba | 2015-08-12 | Marcus Agehall | | return new_logger;
}
}
class SocketLogger {
|
f9ef9f | 2015-10-16 | Marcus Agehall | | inherit Logger.BaseJSONLogger;
|
82c8ba | 2015-08-12 | Marcus Agehall | |
multiset(object) listeners = (<>);
array(object) ports;
mapping(string:object) ports_by_path = ([]);
class LogClient {
Stdio.File sock;
Stdio.Buffer output = Stdio.Buffer(4096);
int write(string|Stdio.Buffer data) {
if (stringp(data)) {
data = Stdio.Buffer(data);
}
output->add(data);
sock->set_write_callback(write_cb);
}
protected int write_cb(mixed self, Stdio.Buffer buff) {
int res = 0;
if (sizeof(output)) {
buff->add(output);
res = sizeof(output);
output->clear();
}
if (!sizeof(buff)) {
sock->set_write_callback(0);
}
return res;
}
protected void close_cb(mixed self) {
listeners[self] = 0;
object f = self->sock;
f->set_nonblocking(0,0,0);
f->set_id(0);
f->close();
destruct(f);
}
protected void read_cb(mixed self, Stdio.Buffer buf) {
buf->clear();
}
void create(Stdio.File f) {
sock = f;
f->set_id(this);
f->set_buffer_mode(Stdio.Buffer(1024), Stdio.Buffer(4096));
f->set_nonblocking(read_cb, 0, close_cb);
}
};
|
75cb5c | 2015-10-16 | Marcus Agehall | | int should_log(string|mapping msg) {
|
82c8ba | 2015-08-12 | Marcus Agehall | |
|
75cb5c | 2015-10-16 | Marcus Agehall | | return ::should_log(msg) && sizeof(listeners);
|
82c8ba | 2015-08-12 | Marcus Agehall | | }
void do_log(mapping entry) {
string res = Standards.JSON.encode(entry);
Stdio.Buffer tmp = Stdio.Buffer(res);
tmp->add("\n");
sizeof(listeners) && indices(listeners)->write(tmp);
}
void accept_cb(object port) {
object l = port->accept();
l = LogClient(l);
listeners[l] = 1;
}
array get_bound_ports() {
return indices(ports_by_path);
}
object bind(string socket_path) {
if (ports_by_path[socket_path]) {
werror("Port already bound for logger!\n");
return UNDEFINED;
}
Stdio.Port port = Stdio.Port();
port->set_id(port);
if (search(socket_path, ":") == -1) {
int res = port->bind_unix(socket_path, accept_cb);
if (!res) {
werror("Failed to bind socket path %O for configuration logger.\n", socket_path);
return UNDEFINED;
} else {
ports_by_path[socket_path] = port;
return port;
}
} else {
sscanf(socket_path, "%s:%d", string ip, int tcp_port);
switch(ip||"") {
case "":
case "*":
ip = "::";
default:
}
int res = port->bind(tcp_port, accept_cb, ip, 1);
if (res != 1) {
werror("Failed to bind log port!\n%s\n", strerror(port->errno()));
} else {
ports_by_path[socket_path] = port;
return port;
}
}
}
int unbind(string|object socket) {
if (stringp(socket)) {
socket = ports_by_path[socket];
}
if (!objectp(socket)) {
werror("Invalid log socket used in unbind request.\n");
return 0;
}
foreach(ports_by_path; string path; Stdio.Port p) {
if (p == socket) {
p->close();
if (Stdio.exist(path)) {
if (!rm(path)) {
werror("Failed to remove log socket %s\n", path);
}
}
m_delete(ports_by_path, path);
destruct(p);
return 1;
}
}
return 0;
}
void unbind_all() {
foreach(ports_by_path; string path; object port) {
unbind(port);
}
}
|
75cb5c | 2015-10-16 | Marcus Agehall | |
BaseJSONLogger child(string logger_name, void|mapping|function defaults) {
logger_name = combine_path_unix(this_program::logger_name, logger_name);
BaseJSONLogger new_logger = BaseJSONLogger(logger_name, defaults, this);
return new_logger;
}
|
f9ef9f | 2015-10-16 | Marcus Agehall | | void create(string logger_name, void|mapping defaults, void|object parent_logger, void|string socket_path) {
::create(logger_name, defaults, parent_logger);
|
82c8ba | 2015-08-12 | Marcus Agehall | |
if (socket_path) {
bind(socket_path);
}
}
void destroy() {
unbind_all();
}
}
|