agoo 2.2.2 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of agoo might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/ext/agoo/agoo.c +2 -2
- data/ext/agoo/con.c +65 -62
- data/ext/agoo/debug.c +3 -2
- data/ext/agoo/extconf.rb +4 -2
- data/ext/agoo/hook.c +15 -74
- data/ext/agoo/hook.h +20 -12
- data/ext/agoo/log.c +30 -466
- data/ext/agoo/log.h +6 -5
- data/ext/agoo/method.h +25 -0
- data/ext/agoo/request.c +27 -23
- data/ext/agoo/request.h +1 -0
- data/ext/agoo/response.c +0 -1
- data/ext/agoo/rhook.c +82 -0
- data/ext/agoo/rhook.h +13 -0
- data/ext/agoo/rlog.c +469 -0
- data/ext/agoo/rlog.h +11 -0
- data/ext/agoo/seg.h +11 -0
- data/ext/agoo/server.c +22 -8
- data/ext/agoo/server.h +1 -1
- data/ext/agoo/types.h +0 -19
- data/ext/agoo/upgraded.c +13 -1
- data/ext/agoo/upgraded.h +2 -1
- data/ext/agoo/websocket.c +3 -3
- data/lib/agoo/version.rb +1 -1
- metadata +9 -3
data/ext/agoo/log.h
CHANGED
@@ -3,15 +3,11 @@
|
|
3
3
|
#ifndef __AGOO_LOG_H__
|
4
4
|
#define __AGOO_LOG_H__
|
5
5
|
|
6
|
-
#include <netdb.h>
|
7
6
|
#include <pthread.h>
|
8
7
|
#include <stdarg.h>
|
9
8
|
#include <stdatomic.h>
|
10
9
|
#include <stdbool.h>
|
11
10
|
#include <stdint.h>
|
12
|
-
#include <stdio.h>
|
13
|
-
|
14
|
-
#include <ruby.h>
|
15
11
|
|
16
12
|
#include "err.h"
|
17
13
|
|
@@ -89,6 +85,8 @@ struct _Log {
|
|
89
85
|
atomic_int wait_state;
|
90
86
|
int rsock;
|
91
87
|
int wsock;
|
88
|
+
|
89
|
+
void (*on_error)(Err err);
|
92
90
|
};
|
93
91
|
|
94
92
|
extern struct _Log the_log;
|
@@ -103,7 +101,8 @@ extern struct _LogCat resp_cat;
|
|
103
101
|
extern struct _LogCat eval_cat;
|
104
102
|
extern struct _LogCat push_cat;
|
105
103
|
|
106
|
-
extern void log_init(
|
104
|
+
extern void log_init();
|
105
|
+
extern void open_log_file();
|
107
106
|
|
108
107
|
extern void log_close();
|
109
108
|
extern bool log_flush(double timeout);
|
@@ -119,4 +118,6 @@ extern void log_catv(LogCat cat, const char *fmt, va_list ap);
|
|
119
118
|
|
120
119
|
extern void log_start(bool with_pid);
|
121
120
|
|
121
|
+
extern Color find_color(const char *name);
|
122
|
+
|
122
123
|
#endif /* __AGOO_LOG_H__ */
|
data/ext/agoo/method.h
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#ifndef __AGOO_METHOD_H__
|
4
|
+
#define __AGOO_METHOD_H__
|
5
|
+
|
6
|
+
typedef enum {
|
7
|
+
CONNECT = 'C',
|
8
|
+
DELETE = 'D',
|
9
|
+
GET = 'G',
|
10
|
+
HEAD = 'H',
|
11
|
+
OPTIONS = 'O',
|
12
|
+
POST = 'P',
|
13
|
+
PUT = 'U',
|
14
|
+
PATCH = 'T',
|
15
|
+
ALL = 'A',
|
16
|
+
NONE = '\0',
|
17
|
+
|
18
|
+
ON_MSG = 'M', // use for on_message callback
|
19
|
+
ON_BIN = 'B', // use for on_message callback with binary (ASCII8BIT)
|
20
|
+
ON_CLOSE = 'X', // use for on_close callback
|
21
|
+
ON_SHUTDOWN = 'S', // use for on_shotdown callback
|
22
|
+
ON_EMPTY = 'E', // use for on_drained callback
|
23
|
+
} Method;
|
24
|
+
|
25
|
+
#endif // __AGOO_METHOD_H__
|
data/ext/agoo/request.c
CHANGED
@@ -64,6 +64,7 @@ request_create(size_t mlen) {
|
|
64
64
|
if (NULL != req) {
|
65
65
|
DEBUG_ALLOC(mem_req, req);
|
66
66
|
memset(req, 0, size);
|
67
|
+
req->env = Qnil;
|
67
68
|
req->mlen = mlen;
|
68
69
|
}
|
69
70
|
return req;
|
@@ -546,30 +547,33 @@ rack_logger(VALUE self) {
|
|
546
547
|
*/
|
547
548
|
VALUE
|
548
549
|
request_env(Req req) {
|
549
|
-
|
550
|
+
if (Qnil == req->env) {
|
551
|
+
volatile VALUE env = rb_hash_new();
|
550
552
|
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
553
|
+
// As described by
|
554
|
+
// http://www.rubydoc.info/github/rack/rack/master/file/SPEC and
|
555
|
+
// https://github.com/rack/rack/blob/master/SPEC.
|
556
|
+
|
557
|
+
rb_hash_aset(env, request_method_val, req_method(req));
|
558
|
+
rb_hash_aset(env, script_name_val, req_script_name(req));
|
559
|
+
rb_hash_aset(env, path_info_val, req_path_info(req));
|
560
|
+
rb_hash_aset(env, query_string_val, req_query_string(req));
|
561
|
+
rb_hash_aset(env, server_name_val, req_server_name(req));
|
562
|
+
rb_hash_aset(env, server_port_val, req_server_port(req));
|
563
|
+
fill_headers(req, env);
|
564
|
+
rb_hash_aset(env, rack_version_val, rack_version_val_val);
|
565
|
+
rb_hash_aset(env, rack_url_scheme_val, req_rack_url_scheme(req));
|
566
|
+
rb_hash_aset(env, rack_input_val, req_rack_input(req));
|
567
|
+
rb_hash_aset(env, rack_errors_val, req_rack_errors(req));
|
568
|
+
rb_hash_aset(env, rack_multithread_val, req_rack_multithread(req));
|
569
|
+
rb_hash_aset(env, rack_multiprocess_val, Qfalse);
|
570
|
+
rb_hash_aset(env, rack_run_once_val, Qfalse);
|
571
|
+
rb_hash_aset(env, rack_logger_val, req_rack_logger(req));
|
572
|
+
rb_hash_aset(env, rack_upgrade_val, req_rack_upgrade(req));
|
573
|
+
|
574
|
+
req->env = env;
|
575
|
+
}
|
576
|
+
return req->env;
|
573
577
|
}
|
574
578
|
|
575
579
|
/* Document-method: to_h
|
data/ext/agoo/request.h
CHANGED
data/ext/agoo/response.c
CHANGED
data/ext/agoo/rhook.c
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <string.h>
|
5
|
+
|
6
|
+
#include <ruby.h>
|
7
|
+
|
8
|
+
#include "debug.h"
|
9
|
+
#include "rhook.h"
|
10
|
+
#include "hook.h"
|
11
|
+
|
12
|
+
static VALUE
|
13
|
+
resolve_classname(VALUE mod, const char *classname) {
|
14
|
+
VALUE clas;
|
15
|
+
ID ci = rb_intern(classname);
|
16
|
+
|
17
|
+
if (rb_const_defined_at(mod, ci)) {
|
18
|
+
clas = rb_const_get_at(mod, ci);
|
19
|
+
} else {
|
20
|
+
clas = Qundef;
|
21
|
+
}
|
22
|
+
return clas;
|
23
|
+
}
|
24
|
+
|
25
|
+
static VALUE
|
26
|
+
resolve_classpath(const char *name, size_t len) {
|
27
|
+
char class_name[1024];
|
28
|
+
VALUE clas;
|
29
|
+
char *end = class_name + sizeof(class_name) - 1;
|
30
|
+
char *s;
|
31
|
+
const char *n = name;
|
32
|
+
|
33
|
+
clas = rb_cObject;
|
34
|
+
for (s = class_name; 0 < len; n++, len--) {
|
35
|
+
if (':' == *n) {
|
36
|
+
*s = '\0';
|
37
|
+
n++;
|
38
|
+
len--;
|
39
|
+
if (':' != *n) {
|
40
|
+
return Qundef;
|
41
|
+
}
|
42
|
+
if (Qundef == (clas = resolve_classname(clas, class_name))) {
|
43
|
+
return Qundef;
|
44
|
+
}
|
45
|
+
s = class_name;
|
46
|
+
} else if (end <= s) {
|
47
|
+
return Qundef;
|
48
|
+
} else {
|
49
|
+
*s++ = *n;
|
50
|
+
}
|
51
|
+
}
|
52
|
+
*s = '\0';
|
53
|
+
return resolve_classname(clas, class_name);
|
54
|
+
}
|
55
|
+
|
56
|
+
Hook
|
57
|
+
rhook_create(Method method, const char *pattern, VALUE handler) {
|
58
|
+
Hook hook = hook_create(method,pattern, NULL, RACK_HOOK);
|
59
|
+
|
60
|
+
if (NULL != hook) {
|
61
|
+
if (T_STRING == rb_type(handler)) {
|
62
|
+
handler = resolve_classpath(StringValuePtr(handler), RSTRING_LEN(handler));
|
63
|
+
// TBD does class handle it or should an instance be made?
|
64
|
+
//
|
65
|
+
}
|
66
|
+
hook->handler = (void*)handler;
|
67
|
+
rb_gc_register_address(&handler);
|
68
|
+
if (rb_respond_to(handler, rb_intern("on_request"))) {
|
69
|
+
hook->type = BASE_HOOK;
|
70
|
+
} else if (rb_respond_to(handler, rb_intern("call"))) {
|
71
|
+
hook->type = RACK_HOOK;
|
72
|
+
} else if (rb_respond_to(handler, rb_intern("create")) &&
|
73
|
+
rb_respond_to(handler, rb_intern("read")) &&
|
74
|
+
rb_respond_to(handler, rb_intern("update")) &&
|
75
|
+
rb_respond_to(handler, rb_intern("delete"))) {
|
76
|
+
hook->type = WAB_HOOK;
|
77
|
+
} else {
|
78
|
+
rb_raise(rb_eArgError, "handler does not have a on_request, or call method nor is it a WAB::Controller");
|
79
|
+
}
|
80
|
+
}
|
81
|
+
return hook;
|
82
|
+
}
|
data/ext/agoo/rhook.h
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#ifndef __AGOO_RHOOK_H__
|
4
|
+
#define __AGOO_RHOOK_H__
|
5
|
+
|
6
|
+
#include <ruby.h>
|
7
|
+
|
8
|
+
#include "hook.h"
|
9
|
+
#include "method.h"
|
10
|
+
|
11
|
+
extern Hook rhook_create(Method method, const char *pattern, VALUE handler);
|
12
|
+
|
13
|
+
#endif // __AGOO_RHOOK_H__
|
data/ext/agoo/rlog.c
ADDED
@@ -0,0 +1,469 @@
|
|
1
|
+
// Copyright 2018 by Peter Ohler, All Rights Reserved
|
2
|
+
|
3
|
+
#include <dirent.h>
|
4
|
+
#include <fcntl.h>
|
5
|
+
#include <poll.h>
|
6
|
+
#include <stdio.h>
|
7
|
+
#include <stdlib.h>
|
8
|
+
#include <string.h>
|
9
|
+
#include <sys/stat.h>
|
10
|
+
#include <sys/time.h>
|
11
|
+
#include <sys/types.h>
|
12
|
+
#include <time.h>
|
13
|
+
#include <unistd.h>
|
14
|
+
|
15
|
+
#include "debug.h"
|
16
|
+
#include "dtime.h"
|
17
|
+
#include "rlog.h"
|
18
|
+
|
19
|
+
static VALUE log_mod = Qundef;
|
20
|
+
|
21
|
+
/* Document-method: configure
|
22
|
+
*
|
23
|
+
* call-seq: configure(options)
|
24
|
+
*
|
25
|
+
* Configures the logger
|
26
|
+
*
|
27
|
+
* - *options* [_Hash_] server options
|
28
|
+
*
|
29
|
+
* - *:dir* [_String_] directory to place log files in. If nil or empty then no log files are written.
|
30
|
+
*
|
31
|
+
* - *:console* [_true_|_false_] if true log entry are display on the console.
|
32
|
+
*
|
33
|
+
* - *:classic* [_true_|_false_] if true log entry follow a classic format. If false log entries are JSON.
|
34
|
+
*
|
35
|
+
* - *:colorize* [_true_|_false_] if true log entries are colorized.
|
36
|
+
*
|
37
|
+
* - *:states* [_Hash_] a map of logging categories and whether they should be on or off. Categories are:
|
38
|
+
* - *:ERROR* errors
|
39
|
+
* - *:WARN* warnings
|
40
|
+
* - *:INFO* infomational
|
41
|
+
* - *:DEBUG* debugging
|
42
|
+
* - *:connect* openning and closing of connections
|
43
|
+
* - *:request* requests
|
44
|
+
* - *:response* responses
|
45
|
+
* - *:eval* handler evaluationss
|
46
|
+
* - *:push* writes to WebSocket or SSE connection
|
47
|
+
*/
|
48
|
+
static VALUE
|
49
|
+
rlog_configure(VALUE self, VALUE options) {
|
50
|
+
if (Qnil != options) {
|
51
|
+
VALUE v;
|
52
|
+
|
53
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("dir"))))) {
|
54
|
+
rb_check_type(v, T_STRING);
|
55
|
+
strncpy(the_log.dir, StringValuePtr(v), sizeof(the_log.dir));
|
56
|
+
the_log.dir[sizeof(the_log.dir) - 1] = '\0';
|
57
|
+
}
|
58
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("max_files"))))) {
|
59
|
+
int max = FIX2INT(v);
|
60
|
+
|
61
|
+
if (1 <= max || max < 100) {
|
62
|
+
the_log.max_files = max;
|
63
|
+
} else {
|
64
|
+
rb_raise(rb_eArgError, "max_files must be between 1 and 100.");
|
65
|
+
}
|
66
|
+
}
|
67
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("max_size"))))) {
|
68
|
+
int max = FIX2INT(v);
|
69
|
+
|
70
|
+
if (1 <= max) {
|
71
|
+
the_log.max_size = max;
|
72
|
+
} else {
|
73
|
+
rb_raise(rb_eArgError, "max_size must be 1 or more.");
|
74
|
+
}
|
75
|
+
}
|
76
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("console"))))) {
|
77
|
+
the_log.console = (Qtrue == v);
|
78
|
+
}
|
79
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("classic"))))) {
|
80
|
+
the_log.classic = (Qtrue == v);
|
81
|
+
}
|
82
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("colorize"))))) {
|
83
|
+
the_log.colorize = (Qtrue == v);
|
84
|
+
}
|
85
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("states"))))) {
|
86
|
+
if (T_HASH == rb_type(v)) {
|
87
|
+
LogCat cat = the_log.cats;
|
88
|
+
VALUE cv;
|
89
|
+
|
90
|
+
for (; NULL != cat; cat = cat->next) {
|
91
|
+
if (Qnil != (cv = rb_hash_lookup(v, ID2SYM(rb_intern(cat->label))))) {
|
92
|
+
if (Qtrue == cv) {
|
93
|
+
cat->on = true;
|
94
|
+
} else if (Qfalse == cv) {
|
95
|
+
cat->on = false;
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
} else {
|
100
|
+
rb_raise(rb_eArgError, "states must be a Hash.");
|
101
|
+
}
|
102
|
+
}
|
103
|
+
}
|
104
|
+
if (NULL != the_log.file) {
|
105
|
+
fclose(the_log.file);
|
106
|
+
the_log.file = NULL;
|
107
|
+
}
|
108
|
+
if ('\0' != *the_log.dir) {
|
109
|
+
if (0 != mkdir(the_log.dir, 0770) && EEXIST != errno) {
|
110
|
+
rb_raise(rb_eIOError, "Failed to create '%s'.", the_log.dir);
|
111
|
+
}
|
112
|
+
open_log_file();
|
113
|
+
}
|
114
|
+
return Qnil;
|
115
|
+
}
|
116
|
+
|
117
|
+
/* Document-method: shutdown
|
118
|
+
*
|
119
|
+
* call-seq: shutdown()
|
120
|
+
*
|
121
|
+
* Shutdown the logger. Writes are flushed before shutting down.
|
122
|
+
*/
|
123
|
+
static VALUE
|
124
|
+
rlog_shutdown(VALUE self) {
|
125
|
+
log_close();
|
126
|
+
return Qnil;
|
127
|
+
}
|
128
|
+
|
129
|
+
/* Document-method: error?
|
130
|
+
*
|
131
|
+
* call-seq: error?()
|
132
|
+
*
|
133
|
+
* Returns true is errors are being logged.
|
134
|
+
*/
|
135
|
+
static VALUE
|
136
|
+
rlog_errorp(VALUE self) {
|
137
|
+
return error_cat.on ? Qtrue : Qfalse;
|
138
|
+
}
|
139
|
+
|
140
|
+
/* Document-method: warn?
|
141
|
+
*
|
142
|
+
* call-seq: warn?()
|
143
|
+
*
|
144
|
+
* Returns true is warnings are being logged.
|
145
|
+
*/
|
146
|
+
static VALUE
|
147
|
+
rlog_warnp(VALUE self) {
|
148
|
+
return warn_cat.on ? Qtrue : Qfalse;
|
149
|
+
}
|
150
|
+
|
151
|
+
/* Document-method: info?
|
152
|
+
*
|
153
|
+
* call-seq: info?()
|
154
|
+
*
|
155
|
+
* Returns true is info entries are being logged.
|
156
|
+
*/
|
157
|
+
static VALUE
|
158
|
+
rlog_infop(VALUE self) {
|
159
|
+
return info_cat.on ? Qtrue : Qfalse;
|
160
|
+
}
|
161
|
+
|
162
|
+
/* Document-method: debug?
|
163
|
+
*
|
164
|
+
* call-seq: debug?()
|
165
|
+
*
|
166
|
+
* Returns true is debug entries are being logged.
|
167
|
+
*/
|
168
|
+
static VALUE
|
169
|
+
rlog_debugp(VALUE self) {
|
170
|
+
return debug_cat.on ? Qtrue : Qfalse;
|
171
|
+
}
|
172
|
+
|
173
|
+
/* Document-method: error
|
174
|
+
*
|
175
|
+
* call-seq: error(msg)
|
176
|
+
*
|
177
|
+
* Log an error message.
|
178
|
+
*/
|
179
|
+
static VALUE
|
180
|
+
rlog_error(VALUE self, VALUE msg) {
|
181
|
+
log_cat(&error_cat, "%s", StringValuePtr(msg));
|
182
|
+
return Qnil;
|
183
|
+
}
|
184
|
+
|
185
|
+
/* Document-method: warn
|
186
|
+
*
|
187
|
+
* call-seq: warn(msg)
|
188
|
+
*
|
189
|
+
* Log a warn message.
|
190
|
+
*/
|
191
|
+
static VALUE
|
192
|
+
rlog_warn(VALUE self, VALUE msg) {
|
193
|
+
log_cat(&warn_cat, "%s", StringValuePtr(msg));
|
194
|
+
return Qnil;
|
195
|
+
}
|
196
|
+
|
197
|
+
/* Document-method: info
|
198
|
+
*
|
199
|
+
* call-seq: info(msg)
|
200
|
+
*
|
201
|
+
* Log an info message.
|
202
|
+
*/
|
203
|
+
static VALUE
|
204
|
+
rlog_info(VALUE self, VALUE msg) {
|
205
|
+
log_cat(&info_cat, "%s", StringValuePtr(msg));
|
206
|
+
return Qnil;
|
207
|
+
}
|
208
|
+
|
209
|
+
/* Document-method: debug
|
210
|
+
*
|
211
|
+
* call-seq: debug(msg)
|
212
|
+
*
|
213
|
+
* Log a debug message.
|
214
|
+
*/
|
215
|
+
static VALUE
|
216
|
+
rlog_debug(VALUE self, VALUE msg) {
|
217
|
+
log_cat(&debug_cat, "%s", StringValuePtr(msg));
|
218
|
+
return Qnil;
|
219
|
+
}
|
220
|
+
|
221
|
+
/* Document-method: color
|
222
|
+
*
|
223
|
+
* call-seq: color(label)
|
224
|
+
*
|
225
|
+
* Returns the current color name as a Symbol for the specified label.
|
226
|
+
*/
|
227
|
+
static VALUE
|
228
|
+
rlog_color_get(VALUE self, VALUE label) {
|
229
|
+
LogCat cat = log_cat_find(StringValuePtr(label));
|
230
|
+
|
231
|
+
if (NULL == cat) {
|
232
|
+
return Qnil;
|
233
|
+
}
|
234
|
+
return ID2SYM(rb_intern(cat->color->name));
|
235
|
+
}
|
236
|
+
|
237
|
+
/* Document-method: set_color
|
238
|
+
*
|
239
|
+
* call-seq: set_color(label, color_symbol)
|
240
|
+
*
|
241
|
+
* Sets color of the category associated with a label. Valid colors are
|
242
|
+
* :black, :red, :green, :yellow, :blue, :magenta, :cyan, :white, :gray,
|
243
|
+
* :dark_red, :dark_green, :brown, :dark_blue, :purple, and :dark_cyan.
|
244
|
+
*/
|
245
|
+
static VALUE
|
246
|
+
rlog_color_set(VALUE self, VALUE label, VALUE color) {
|
247
|
+
const char *label_str = StringValuePtr(label);
|
248
|
+
const char *color_name = StringValuePtr(color);
|
249
|
+
LogCat cat = log_cat_find(label_str);
|
250
|
+
Color c = find_color(color_name);
|
251
|
+
|
252
|
+
if (NULL == cat) {
|
253
|
+
rb_raise(rb_eArgError, "%s is not a valid category.", label_str);
|
254
|
+
}
|
255
|
+
if (NULL == c) {
|
256
|
+
rb_raise(rb_eArgError, "%s is not a valid color.", color_name);
|
257
|
+
}
|
258
|
+
cat->color = c;
|
259
|
+
|
260
|
+
return Qnil;
|
261
|
+
}
|
262
|
+
|
263
|
+
/* Document-method: state
|
264
|
+
*
|
265
|
+
* call-seq: state(label)
|
266
|
+
*
|
267
|
+
* Returns the current state of the category identified by the specified
|
268
|
+
* label.
|
269
|
+
*/
|
270
|
+
static VALUE
|
271
|
+
rlog_on_get(VALUE self, VALUE label) {
|
272
|
+
LogCat cat = log_cat_find(StringValuePtr(label));
|
273
|
+
|
274
|
+
if (NULL == cat) {
|
275
|
+
return Qfalse;
|
276
|
+
}
|
277
|
+
return cat->on ? Qtrue : Qfalse;
|
278
|
+
}
|
279
|
+
|
280
|
+
/* Document-method: set_state
|
281
|
+
*
|
282
|
+
* call-seq: set_state(label, state)
|
283
|
+
*
|
284
|
+
* Sets state of the category associated with a label.
|
285
|
+
*/
|
286
|
+
static VALUE
|
287
|
+
rlog_on_set(VALUE self, VALUE label, VALUE state) {
|
288
|
+
const char *label_str = StringValuePtr(label);
|
289
|
+
LogCat cat = log_cat_find(label_str);
|
290
|
+
|
291
|
+
if (NULL == cat) {
|
292
|
+
rb_raise(rb_eArgError, "%s is not a valid category.", label_str);
|
293
|
+
}
|
294
|
+
cat->on = (Qtrue == state);
|
295
|
+
|
296
|
+
return cat->on ? Qtrue : Qfalse;
|
297
|
+
}
|
298
|
+
|
299
|
+
/* Document-method: log
|
300
|
+
*
|
301
|
+
* call-seq: log[label] = msg
|
302
|
+
*
|
303
|
+
* Log a message in the specified category.
|
304
|
+
*/
|
305
|
+
static VALUE
|
306
|
+
rlog_log(VALUE self, VALUE label, VALUE msg) {
|
307
|
+
const char *label_str = StringValuePtr(label);
|
308
|
+
LogCat cat = log_cat_find(label_str);
|
309
|
+
|
310
|
+
if (NULL == cat) {
|
311
|
+
rb_raise(rb_eArgError, "%s is not a valid category.", label_str);
|
312
|
+
}
|
313
|
+
log_cat(cat, "%s", StringValuePtr(msg));
|
314
|
+
|
315
|
+
return Qnil;
|
316
|
+
}
|
317
|
+
|
318
|
+
/* Document-method: flush
|
319
|
+
*
|
320
|
+
* call-seq: flush
|
321
|
+
*
|
322
|
+
* Flush the log queue and write all entries to disk or the console. The call
|
323
|
+
* waits for the flush to complete or the timeout to be exceeded.
|
324
|
+
*/
|
325
|
+
static VALUE
|
326
|
+
rlog_flush(VALUE self, VALUE to) {
|
327
|
+
double timeout = NUM2DBL(to);
|
328
|
+
|
329
|
+
if (!log_flush(timeout)) {
|
330
|
+
rb_raise(rb_eStandardError, "timed out waiting for log flush.");
|
331
|
+
}
|
332
|
+
return Qnil;
|
333
|
+
}
|
334
|
+
|
335
|
+
/* Document-method: rotate
|
336
|
+
*
|
337
|
+
* call-seq: rotate()
|
338
|
+
*
|
339
|
+
* Rotate the log files.
|
340
|
+
*/
|
341
|
+
static VALUE
|
342
|
+
rlog_rotate(VALUE self) {
|
343
|
+
log_rotate();
|
344
|
+
return Qnil;
|
345
|
+
}
|
346
|
+
|
347
|
+
/* Document-method: console=
|
348
|
+
*
|
349
|
+
* call-seq: console=(on)
|
350
|
+
*
|
351
|
+
* If on then log output also goes to the console.
|
352
|
+
*/
|
353
|
+
static VALUE
|
354
|
+
rlog_console(VALUE self, VALUE on) {
|
355
|
+
the_log.console = (Qtrue == on);
|
356
|
+
return Qnil;
|
357
|
+
}
|
358
|
+
|
359
|
+
/* Document-method: classic
|
360
|
+
*
|
361
|
+
* call-seq: classic()
|
362
|
+
*
|
363
|
+
* Set the log format to classic format.
|
364
|
+
*/
|
365
|
+
static VALUE
|
366
|
+
rlog_classic(VALUE self) {
|
367
|
+
the_log.classic = true;
|
368
|
+
return Qnil;
|
369
|
+
}
|
370
|
+
|
371
|
+
/* Document-method: json
|
372
|
+
*
|
373
|
+
* call-seq: json()
|
374
|
+
*
|
375
|
+
* Set the log format to JSON format.
|
376
|
+
*/
|
377
|
+
static VALUE
|
378
|
+
rlog_json(VALUE self) {
|
379
|
+
the_log.classic = false;
|
380
|
+
return Qnil;
|
381
|
+
}
|
382
|
+
|
383
|
+
/* Document-method: max_size
|
384
|
+
*
|
385
|
+
* call-seq: max_size(size)
|
386
|
+
*
|
387
|
+
* Maximum log files size is reset.
|
388
|
+
*/
|
389
|
+
static VALUE
|
390
|
+
rlog_max_size(VALUE self, VALUE rmax) {
|
391
|
+
int max = FIX2INT(rmax);
|
392
|
+
|
393
|
+
if (1 <= max) {
|
394
|
+
the_log.max_size = max;
|
395
|
+
} else {
|
396
|
+
rb_raise(rb_eArgError, "max_size must be 1 or more.");
|
397
|
+
}
|
398
|
+
return Qnil;
|
399
|
+
}
|
400
|
+
|
401
|
+
/* Document-method: max_files
|
402
|
+
*
|
403
|
+
* call-seq: max_files(max)
|
404
|
+
*
|
405
|
+
* Maximum log files files is reset.
|
406
|
+
*/
|
407
|
+
static VALUE
|
408
|
+
rlog_max_files(VALUE self, VALUE rmax) {
|
409
|
+
int max = FIX2INT(rmax);
|
410
|
+
|
411
|
+
if (1 <= max || max < 100) {
|
412
|
+
the_log.max_files = max;
|
413
|
+
} else {
|
414
|
+
rb_raise(rb_eArgError, "max_files must be between 1 and 100.");
|
415
|
+
}
|
416
|
+
return Qnil;
|
417
|
+
}
|
418
|
+
|
419
|
+
static void
|
420
|
+
on_error(Err err) {
|
421
|
+
rb_raise(rb_eStandardError, "%s", err->msg);
|
422
|
+
}
|
423
|
+
|
424
|
+
/* Document-class: Agoo::Log
|
425
|
+
*
|
426
|
+
* An asynchronous and thread safe logger that includes file rollover and
|
427
|
+
* multiple logging categories. It is a feature based logger with a level
|
428
|
+
* overlay.
|
429
|
+
*/
|
430
|
+
void
|
431
|
+
rlog_init(VALUE mod) {
|
432
|
+
log_mod = rb_define_module_under(mod, "Log");
|
433
|
+
|
434
|
+
rb_define_module_function(log_mod, "configure", rlog_configure, 1);
|
435
|
+
rb_define_module_function(log_mod, "shutdown", rlog_shutdown, 0);
|
436
|
+
|
437
|
+
rb_define_module_function(log_mod, "error?", rlog_errorp, 0);
|
438
|
+
rb_define_module_function(log_mod, "warn?", rlog_warnp, 0);
|
439
|
+
rb_define_module_function(log_mod, "info?", rlog_infop, 0);
|
440
|
+
rb_define_module_function(log_mod, "debug?", rlog_debugp, 0);
|
441
|
+
|
442
|
+
rb_define_module_function(log_mod, "error", rlog_error, 1);
|
443
|
+
rb_define_module_function(log_mod, "warn", rlog_warn, 1);
|
444
|
+
rb_define_module_function(log_mod, "info", rlog_info, 1);
|
445
|
+
rb_define_module_function(log_mod, "debug", rlog_debug, 1);
|
446
|
+
|
447
|
+
// TBD maybe in a future version
|
448
|
+
//rb_define_module_function(log_mod, "register", rlog_register, 2);
|
449
|
+
|
450
|
+
rb_define_module_function(log_mod, "color", rlog_color_get, 1);
|
451
|
+
rb_define_module_function(log_mod, "set_color", rlog_color_set, 2);
|
452
|
+
|
453
|
+
rb_define_module_function(log_mod, "state", rlog_on_get, 1);
|
454
|
+
rb_define_module_function(log_mod, "set_state", rlog_on_set, 2);
|
455
|
+
|
456
|
+
rb_define_module_function(log_mod, "log", rlog_log, 2);
|
457
|
+
|
458
|
+
rb_define_module_function(log_mod, "flush", rlog_flush, 1);
|
459
|
+
rb_define_module_function(log_mod, "rotate", rlog_rotate, 0);
|
460
|
+
rb_define_module_function(log_mod, "console=", rlog_console, 1);
|
461
|
+
rb_define_module_function(log_mod, "classic", rlog_classic, 0);
|
462
|
+
rb_define_module_function(log_mod, "json", rlog_json, 0);
|
463
|
+
rb_define_module_function(log_mod, "max_size=", rlog_max_size, 1);
|
464
|
+
rb_define_module_function(log_mod, "max_files=", rlog_max_files, 1);
|
465
|
+
|
466
|
+
the_log.on_error = on_error;
|
467
|
+
|
468
|
+
log_init();
|
469
|
+
}
|