iodine 0.7.60 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.clang-format +15 -0
- data/.rspec +1 -0
- data/.yardopts +1 -3
- data/CHANGELOG.md +132 -12
- data/Gemfile +5 -7
- data/LICENSE.txt +1 -1
- data/README.md +147 -671
- data/Rakefile +9 -16
- data/examples/chatroom.nru +9 -0
- data/examples/client +74 -0
- data/examples/config-hello.nru +9 -0
- data/examples/config-hello.ru +11 -0
- data/examples/config-hijack.ru +13 -0
- data/examples/config-shootout.ru +43 -0
- data/examples/config.nru +120 -0
- data/examples/config.rb +37 -0
- data/examples/config.ru +42 -53
- data/examples/fake +24 -0
- data/examples/hello_neorack +137 -0
- data/examples/routes.nru +29 -0
- data/examples/routes.ru +42 -0
- data/exe/iodine +218 -258
- data/ext/iodine/extconf.rb +27 -100
- data/ext/iodine/fio-stl.h +128336 -0
- data/ext/iodine/fio-stl.md +26396 -0
- data/ext/iodine/iodine.c +213 -1393
- data/ext/iodine/iodine.h +250 -55
- data/ext/iodine/iodine_arg_helper.h +329 -0
- data/ext/iodine/iodine_caller.h +234 -25
- data/ext/iodine/iodine_cli.h +434 -0
- data/ext/iodine/iodine_compression.h +312 -0
- data/ext/iodine/iodine_connection.h +3484 -34
- data/ext/iodine/iodine_core.h +363 -0
- data/ext/iodine/iodine_crypto.h +1441 -0
- data/ext/iodine/iodine_defer.h +225 -4
- data/ext/iodine/iodine_json.h +738 -4
- data/ext/iodine/iodine_listener.h +263 -0
- data/ext/iodine/iodine_log.h +297 -0
- data/ext/iodine/iodine_minimap.h +543 -0
- data/ext/iodine/iodine_mustache.h +461 -4
- data/ext/iodine/iodine_pubsub_eng.h +729 -0
- data/ext/iodine/iodine_pubsub_history.h +547 -0
- data/ext/iodine/iodine_pubsub_msg.h +228 -0
- data/ext/iodine/iodine_redis.h +322 -0
- data/ext/iodine/iodine_store.h +418 -16
- data/ext/iodine/iodine_threads.h +279 -0
- data/ext/iodine/iodine_tls.h +515 -6
- data/ext/iodine/iodine_utils.h +923 -0
- data/iodine.gemspec +37 -42
- data/lib/iodine/benchmark.rb +1690 -0
- data/lib/iodine/documentation.rb +3085 -0
- data/lib/iodine/version.rb +17 -1
- data/lib/iodine.rb +54 -255
- data/logo.svg +36 -0
- data/mustache.md +55 -0
- data/sig/iodine.rbs +4 -0
- metadata +58 -184
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- data/.github/workflows/ruby.yml +0 -42
- data/.gitignore +0 -21
- data/LIMITS.md +0 -41
- data/SPEC-PubSub-Draft.md +0 -159
- data/SPEC-WebSocket-Draft.md +0 -239
- data/bin/console +0 -22
- data/bin/info.md +0 -353
- data/bin/mustache_bench.rb +0 -100
- data/bin/poc/Gemfile.lock +0 -23
- data/bin/poc/README.md +0 -37
- data/bin/poc/config.ru +0 -66
- data/bin/poc/gemfile +0 -1
- data/bin/poc/www/index.html +0 -57
- data/examples/async_task.ru +0 -92
- data/examples/bates/README.md +0 -3
- data/examples/bates/config.ru +0 -342
- data/examples/bates/david+bold.pdf +0 -0
- data/examples/bates/public/drop-pdf.png +0 -0
- data/examples/bates/public/index.html +0 -600
- data/examples/echo.ru +0 -59
- data/examples/etag.ru +0 -16
- data/examples/hello.ru +0 -29
- data/examples/pubsub_engine.ru +0 -81
- data/examples/rack3.ru +0 -12
- data/examples/redis.ru +0 -70
- data/examples/shootout.ru +0 -73
- data/examples/sub-protocols.ru +0 -90
- data/examples/tcp_client.rb +0 -66
- data/examples/x-sendfile.ru +0 -14
- data/ext/iodine/fio.c +0 -11995
- data/ext/iodine/fio.h +0 -6371
- data/ext/iodine/fio_cli.c +0 -431
- data/ext/iodine/fio_cli.h +0 -189
- data/ext/iodine/fio_json_parser.h +0 -688
- data/ext/iodine/fio_siphash.c +0 -157
- data/ext/iodine/fio_siphash.h +0 -37
- data/ext/iodine/fio_tls.h +0 -129
- data/ext/iodine/fio_tls_missing.c +0 -649
- data/ext/iodine/fio_tls_openssl.c +0 -1106
- data/ext/iodine/fio_tmpfile.h +0 -50
- data/ext/iodine/fiobj.h +0 -44
- data/ext/iodine/fiobj4fio.h +0 -21
- data/ext/iodine/fiobj_ary.c +0 -333
- data/ext/iodine/fiobj_ary.h +0 -139
- data/ext/iodine/fiobj_data.c +0 -1187
- data/ext/iodine/fiobj_data.h +0 -167
- data/ext/iodine/fiobj_hash.c +0 -409
- data/ext/iodine/fiobj_hash.h +0 -176
- data/ext/iodine/fiobj_json.c +0 -622
- data/ext/iodine/fiobj_json.h +0 -68
- data/ext/iodine/fiobj_mem.h +0 -71
- data/ext/iodine/fiobj_mustache.c +0 -317
- data/ext/iodine/fiobj_mustache.h +0 -62
- data/ext/iodine/fiobj_numbers.c +0 -344
- data/ext/iodine/fiobj_numbers.h +0 -127
- data/ext/iodine/fiobj_str.c +0 -433
- data/ext/iodine/fiobj_str.h +0 -172
- data/ext/iodine/fiobject.c +0 -620
- data/ext/iodine/fiobject.h +0 -655
- data/ext/iodine/hpack.h +0 -1923
- data/ext/iodine/http.c +0 -2743
- data/ext/iodine/http.h +0 -1002
- data/ext/iodine/http1.c +0 -910
- data/ext/iodine/http1.h +0 -29
- data/ext/iodine/http1_parser.h +0 -878
- data/ext/iodine/http_internal.c +0 -1279
- data/ext/iodine/http_internal.h +0 -237
- data/ext/iodine/http_mime_parser.h +0 -350
- data/ext/iodine/iodine_caller.c +0 -230
- data/ext/iodine/iodine_connection.c +0 -941
- data/ext/iodine/iodine_defer.c +0 -420
- data/ext/iodine/iodine_fiobj2rb.h +0 -120
- data/ext/iodine/iodine_helpers.c +0 -282
- data/ext/iodine/iodine_helpers.h +0 -12
- data/ext/iodine/iodine_http.c +0 -1181
- data/ext/iodine/iodine_http.h +0 -23
- data/ext/iodine/iodine_json.c +0 -302
- data/ext/iodine/iodine_mustache.c +0 -567
- data/ext/iodine/iodine_pubsub.c +0 -580
- data/ext/iodine/iodine_pubsub.h +0 -26
- data/ext/iodine/iodine_rack_io.c +0 -273
- data/ext/iodine/iodine_rack_io.h +0 -20
- data/ext/iodine/iodine_store.c +0 -148
- data/ext/iodine/iodine_tcp.c +0 -346
- data/ext/iodine/iodine_tcp.h +0 -13
- data/ext/iodine/iodine_tls.c +0 -261
- data/ext/iodine/mustache_parser.h +0 -1546
- data/ext/iodine/redis_engine.c +0 -957
- data/ext/iodine/redis_engine.h +0 -79
- data/ext/iodine/resp_parser.h +0 -317
- data/ext/iodine/websocket_parser.h +0 -506
- data/ext/iodine/websockets.c +0 -743
- data/ext/iodine/websockets.h +0 -185
- data/lib/iodine/connection.rb +0 -61
- data/lib/iodine/json.rb +0 -42
- data/lib/iodine/mustache.rb +0 -113
- data/lib/iodine/pubsub.rb +0 -55
- data/lib/iodine/rack_utils.rb +0 -43
- data/lib/iodine/tls.rb +0 -16
- data/lib/rack/handler/iodine.rb +0 -33
- data/logo.png +0 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
#ifndef H___IODINE_LISTENER___H
|
|
2
|
+
#define H___IODINE_LISTENER___H
|
|
3
|
+
#include "iodine.h"
|
|
4
|
+
|
|
5
|
+
/* *****************************************************************************
|
|
6
|
+
Iodine Listener - Server Socket Listener Management
|
|
7
|
+
|
|
8
|
+
This module provides the Iodine::Listener Ruby class which represents an
|
|
9
|
+
active server socket listener. Listeners are created via Iodine.listen()
|
|
10
|
+
and can be used to:
|
|
11
|
+
|
|
12
|
+
- Map URL routes to different handlers (for HTTP listeners)
|
|
13
|
+
- Get/set the handler for raw TCP/WebSocket connections
|
|
14
|
+
- Manage listener lifecycle
|
|
15
|
+
|
|
16
|
+
The Listener class wraps either:
|
|
17
|
+
- fio_http_listener_s for HTTP/WebSocket listeners
|
|
18
|
+
- fio_io_listener_s for raw TCP listeners
|
|
19
|
+
|
|
20
|
+
Ruby API (Iodine::Listener):
|
|
21
|
+
- listener.map(url: "/path", handler: obj) - Map URL to handler (HTTP only)
|
|
22
|
+
- listener.map - Get current handler
|
|
23
|
+
|
|
24
|
+
Note: Listeners can only be created via Iodine.listen(), not directly
|
|
25
|
+
instantiated.
|
|
26
|
+
***************************************************************************** */
|
|
27
|
+
|
|
28
|
+
/* *****************************************************************************
|
|
29
|
+
Ruby Object
|
|
30
|
+
***************************************************************************** */
|
|
31
|
+
|
|
32
|
+
/** The Iodine::Listener Ruby class */
|
|
33
|
+
static VALUE iodine_rb_IODINE_LISTENER;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Internal structure representing an Iodine listener.
|
|
37
|
+
*
|
|
38
|
+
* Wraps either an HTTP listener (fio_http_listener_s) or a raw IO listener
|
|
39
|
+
* (fio_io_listener_s) along with its Ruby handler object.
|
|
40
|
+
*/
|
|
41
|
+
typedef struct {
|
|
42
|
+
void *listener; /**< Pointer to fio_http_listener_s or fio_io_listener_s */
|
|
43
|
+
VALUE handler; /**< Ruby handler object for callbacks */
|
|
44
|
+
bool is_http; /**< true if HTTP listener, false if raw TCP */
|
|
45
|
+
} iodine_listener_s;
|
|
46
|
+
|
|
47
|
+
static void iodine_listener_free(void *p) {
|
|
48
|
+
iodine_listener_s *m = (iodine_listener_s *)p;
|
|
49
|
+
ruby_xfree(m);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static size_t iodine_listener_size(const void *p) {
|
|
53
|
+
iodine_listener_s *m = (iodine_listener_s *)p;
|
|
54
|
+
return sizeof(*m);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
FIO_IFUNC void iodine_listener_gc_mark(void *p) {
|
|
58
|
+
iodine_listener_s *m = (iodine_listener_s *)p;
|
|
59
|
+
if (!IODINE_STORE_IS_SKIP(m->handler))
|
|
60
|
+
rb_gc_mark(m->handler);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static const rb_data_type_t IODINE_LISTNER_DATA_TYPE = {
|
|
64
|
+
.wrap_struct_name = "IodineListner",
|
|
65
|
+
.function =
|
|
66
|
+
{
|
|
67
|
+
.dmark = iodine_listener_gc_mark,
|
|
68
|
+
.dfree = iodine_listener_free,
|
|
69
|
+
.dsize = iodine_listener_size,
|
|
70
|
+
},
|
|
71
|
+
.data = NULL,
|
|
72
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
static iodine_listener_s *iodine_listener_ptr(VALUE self) {
|
|
76
|
+
iodine_listener_s *m;
|
|
77
|
+
TypedData_Get_Struct(self, iodine_listener_s, &IODINE_LISTNER_DATA_TYPE, m);
|
|
78
|
+
return m;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
static VALUE iodine_listener_alloc(VALUE klass) {
|
|
82
|
+
iodine_listener_s *m;
|
|
83
|
+
VALUE self = TypedData_Make_Struct(klass,
|
|
84
|
+
iodine_listener_s,
|
|
85
|
+
&IODINE_LISTNER_DATA_TYPE,
|
|
86
|
+
m);
|
|
87
|
+
*m = (iodine_listener_s){0};
|
|
88
|
+
return self;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* *****************************************************************************
|
|
92
|
+
Helpers - Internal Handler Management
|
|
93
|
+
***************************************************************************** */
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Macro called when a listener's handler is set.
|
|
97
|
+
* Releases the old handler from the store and holds the new one.
|
|
98
|
+
* Also injects handler methods into the listener class.
|
|
99
|
+
*/
|
|
100
|
+
#define IODINE_LISTNER_ONSET(o) \
|
|
101
|
+
do { \
|
|
102
|
+
STORE.release(old_value); \
|
|
103
|
+
STORE.hold(o->handler); \
|
|
104
|
+
iodine_handler_method_injection__inner(iodine_rb_IODINE_LISTENER, \
|
|
105
|
+
o->handler, \
|
|
106
|
+
0); \
|
|
107
|
+
} while (0)
|
|
108
|
+
|
|
109
|
+
FIO_DEF_GETSET_FUNC(static,
|
|
110
|
+
iodine___listener,
|
|
111
|
+
iodine_listener_s,
|
|
112
|
+
VALUE,
|
|
113
|
+
handler,
|
|
114
|
+
IODINE_LISTNER_ONSET)
|
|
115
|
+
|
|
116
|
+
#undef IODINE_LISTNER_ONSET
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Creates a new Iodine::Listener Ruby object wrapping a native listener.
|
|
120
|
+
*
|
|
121
|
+
* This is called internally by Iodine.listen() to create the Ruby wrapper.
|
|
122
|
+
*
|
|
123
|
+
* @param listener Pointer to the native listener (HTTP or raw)
|
|
124
|
+
* @param handler Ruby handler object for callbacks
|
|
125
|
+
* @param is_http true for HTTP listeners, false for raw TCP
|
|
126
|
+
* @return New Iodine::Listener VALUE
|
|
127
|
+
*
|
|
128
|
+
* @note Raises NoMemError if allocation fails.
|
|
129
|
+
*/
|
|
130
|
+
static VALUE iodine_listener_new(void *listener, VALUE handler, bool is_http) {
|
|
131
|
+
VALUE r = iodine_listener_alloc(iodine_rb_IODINE_LISTENER);
|
|
132
|
+
if (IODINE_STORE_IS_SKIP(r))
|
|
133
|
+
rb_raise(rb_eNoMemError, "Listener loocation error!");
|
|
134
|
+
iodine_listener_s *l = iodine_listener_ptr(r);
|
|
135
|
+
*l = (iodine_listener_s){.listener = listener,
|
|
136
|
+
.handler = handler,
|
|
137
|
+
.is_http = is_http};
|
|
138
|
+
return r;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* *****************************************************************************
|
|
142
|
+
API - Ruby Methods
|
|
143
|
+
***************************************************************************** */
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Maps a URL path to a handler or retrieves the current handler.
|
|
147
|
+
*
|
|
148
|
+
* For HTTP listeners:
|
|
149
|
+
* - With url and handler: Maps the URL path to the handler
|
|
150
|
+
* - With url only: Returns the handler for that URL path
|
|
151
|
+
* - With neither: Returns the default handler
|
|
152
|
+
*
|
|
153
|
+
* For raw TCP listeners:
|
|
154
|
+
* - URL parameter is not allowed (raises RuntimeError)
|
|
155
|
+
* - With handler: Sets the connection handler
|
|
156
|
+
* - Without handler: Returns the current handler
|
|
157
|
+
*
|
|
158
|
+
* @param argc Number of arguments
|
|
159
|
+
* @param argv Array of arguments (url:, handler:)
|
|
160
|
+
* @param o The Iodine::Listener instance
|
|
161
|
+
* @return The handler for the specified URL/listener
|
|
162
|
+
*
|
|
163
|
+
* @note Raises RuntimeError if called on an inactive listener.
|
|
164
|
+
* @note Raises RuntimeError if URL is provided for non-HTTP listener.
|
|
165
|
+
*
|
|
166
|
+
* Ruby: listener.map(url: "/api", handler: MyHandler)
|
|
167
|
+
* listener.map(url: "/api") # => returns handler
|
|
168
|
+
* listener.map # => returns default handler
|
|
169
|
+
*/
|
|
170
|
+
static VALUE iodine_listener_map(int argc, VALUE *argv, VALUE o) {
|
|
171
|
+
iodine_listener_s *l = iodine_listener_ptr(o);
|
|
172
|
+
fio_http_settings_s settings;
|
|
173
|
+
VALUE url = Qnil;
|
|
174
|
+
VALUE handler = Qnil;
|
|
175
|
+
|
|
176
|
+
iodine_rb2c_arg(argc,
|
|
177
|
+
argv,
|
|
178
|
+
IODINE_ARG_RB(url, 0, "url", 0),
|
|
179
|
+
IODINE_ARG_RB(handler, 0, "handler", 0));
|
|
180
|
+
if (!l->listener)
|
|
181
|
+
rb_raise(rb_eRuntimeError,
|
|
182
|
+
"call to `map` can only be called on active listeners");
|
|
183
|
+
if (l->is_http) {
|
|
184
|
+
if (RB_TYPE_P(url, RUBY_T_SYMBOL))
|
|
185
|
+
url = rb_sym2str(rb_sym2id(url));
|
|
186
|
+
if (!IODINE_STORE_IS_SKIP(url))
|
|
187
|
+
rb_check_type(url, RUBY_T_STRING);
|
|
188
|
+
if (handler == Qnil) { /* read value */
|
|
189
|
+
handler = (VALUE)(fio_http_route_settings(
|
|
190
|
+
(fio_http_listener_s *)(l->listener),
|
|
191
|
+
IODINE_STORE_IS_SKIP(url) ? "/" : RSTRING_PTR(url))
|
|
192
|
+
->udata);
|
|
193
|
+
} else { /* set value for HTTP router */
|
|
194
|
+
if (!IODINE_STORE_IS_SKIP(handler)) {
|
|
195
|
+
STORE.hold(handler);
|
|
196
|
+
iodine_handler_method_injection__inner(iodine_rb_IODINE_LISTENER,
|
|
197
|
+
handler,
|
|
198
|
+
0);
|
|
199
|
+
}
|
|
200
|
+
settings =
|
|
201
|
+
*fio_http_listener_settings((fio_http_listener_s *)l->listener);
|
|
202
|
+
if (IODINE_STORE_IS_SKIP(handler))
|
|
203
|
+
handler = (VALUE)settings.udata;
|
|
204
|
+
settings.udata = (void *)handler;
|
|
205
|
+
settings.public_folder = FIO_STR_INFO0;
|
|
206
|
+
// TODO: test for a handler's public folder property?
|
|
207
|
+
fio_http_route FIO_NOOP((fio_http_listener_s *)l->listener,
|
|
208
|
+
RSTRING_PTR(url),
|
|
209
|
+
settings);
|
|
210
|
+
}
|
|
211
|
+
} else { /* not HTTP, URLs are invalid. */
|
|
212
|
+
if (!IODINE_STORE_IS_SKIP(url))
|
|
213
|
+
rb_raise(rb_eRuntimeError,
|
|
214
|
+
"URL values are only valid for HTTP listener objects.");
|
|
215
|
+
if (handler == Qnil) { /* read value */
|
|
216
|
+
handler = iodine___listener_handler(l);
|
|
217
|
+
} else { /* set value for raw router */
|
|
218
|
+
fio_io_listener_udata_set((fio_io_listener_s *)(l->listener),
|
|
219
|
+
(void *)handler);
|
|
220
|
+
iodine___listener_handler_set(l, handler);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return handler;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Raises an error - Listeners cannot be directly instantiated.
|
|
228
|
+
*
|
|
229
|
+
* Listeners must be created via Iodine.listen() which returns a
|
|
230
|
+
* properly configured Listener object.
|
|
231
|
+
*
|
|
232
|
+
* @param o The Listener instance (unused)
|
|
233
|
+
* @return Never returns (always raises)
|
|
234
|
+
*
|
|
235
|
+
* @note Always raises RuntimeError.
|
|
236
|
+
*/
|
|
237
|
+
static VALUE iodine_listener_initialize(VALUE o) {
|
|
238
|
+
rb_raise(rb_eRuntimeError,
|
|
239
|
+
"Iodine Listeners can only be created using Iodine.listen");
|
|
240
|
+
return Qnil;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/* *****************************************************************************
|
|
244
|
+
Initialize - Ruby Class Registration
|
|
245
|
+
***************************************************************************** */
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Initializes the Iodine::Listener Ruby class.
|
|
249
|
+
*
|
|
250
|
+
* Defines the class under the Iodine module and registers:
|
|
251
|
+
* - Allocator function
|
|
252
|
+
* - initialize method (raises error - use Iodine.listen instead)
|
|
253
|
+
* - map method for URL routing (HTTP) or handler access (raw)
|
|
254
|
+
*/
|
|
255
|
+
static void Init_Iodine_Listener(void) {
|
|
256
|
+
VALUE m = iodine_rb_IODINE_LISTENER =
|
|
257
|
+
rb_define_class_under(iodine_rb_IODINE, "Listener", rb_cObject);
|
|
258
|
+
STORE.hold(iodine_rb_IODINE_LISTENER);
|
|
259
|
+
rb_define_alloc_func(m, iodine_listener_alloc);
|
|
260
|
+
rb_define_method(m, "initialize", iodine_listener_initialize, 0);
|
|
261
|
+
rb_define_method(m, "map", iodine_listener_map, -1);
|
|
262
|
+
}
|
|
263
|
+
#endif /* H___IODINE_LISTENER___H */
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
#ifndef H___IODINE_LOG___H
|
|
2
|
+
#define H___IODINE_LOG___H
|
|
3
|
+
#include "iodine.h"
|
|
4
|
+
|
|
5
|
+
/* *****************************************************************************
|
|
6
|
+
Iodine::Logger - Ruby-facing leveled logging
|
|
7
|
+
|
|
8
|
+
Routes Ruby log messages through the facil.io C STL logging system
|
|
9
|
+
(FIO_LOG_*), so Ruby output shares the same stderr sink, level prefixes,
|
|
10
|
+
truncation limits, and the global log level (Iodine::Logger.level /
|
|
11
|
+
FIO_LOG_LEVEL) as the C core.
|
|
12
|
+
|
|
13
|
+
Log levels (from facil.io):
|
|
14
|
+
- 0: FIO_LOG_LEVEL_NONE - No logging
|
|
15
|
+
- 1: FIO_LOG_LEVEL_FATAL - Fatal errors only
|
|
16
|
+
- 2: FIO_LOG_LEVEL_ERROR - Errors and above
|
|
17
|
+
- 3: FIO_LOG_LEVEL_WARNING - Warnings and above
|
|
18
|
+
- 4: FIO_LOG_LEVEL_INFO - Info and above (default)
|
|
19
|
+
- 5: FIO_LOG_LEVEL_DEBUG - Debug and above
|
|
20
|
+
|
|
21
|
+
Ruby API:
|
|
22
|
+
- Iodine::Logger.fatal(*msg, &blk) / .error / .warn / .info / .debug
|
|
23
|
+
(each argument logged separately; callable arguments invoked; a block's
|
|
24
|
+
return value logged; nothing evaluated while the level is silenced)
|
|
25
|
+
- Iodine::Logger << msg (alias for info)
|
|
26
|
+
- Iodine::Logger.level / .level= (Integer 0-5 or Symbol)
|
|
27
|
+
- Iodine::Logger::NONE / FATAL / ERROR / WARN / INFO / DEBUG constants
|
|
28
|
+
***************************************************************************** */
|
|
29
|
+
|
|
30
|
+
static VALUE iodine_rb_IODINE_LOGGER;
|
|
31
|
+
|
|
32
|
+
/* *****************************************************************************
|
|
33
|
+
Leveled logging methods
|
|
34
|
+
***************************************************************************** */
|
|
35
|
+
|
|
36
|
+
/** Emits a single message at the given level through the C STL logging. */
|
|
37
|
+
static void iodine_log_emit_value(int level, VALUE msg) {
|
|
38
|
+
VALUE str = rb_obj_as_string(msg);
|
|
39
|
+
const char *cstr = StringValueCStr(str);
|
|
40
|
+
switch (level) {
|
|
41
|
+
case FIO_LOG_LEVEL_FATAL: FIO_LOG_FATAL("%s", cstr); break;
|
|
42
|
+
case FIO_LOG_LEVEL_ERROR: FIO_LOG_ERROR("%s", cstr); break;
|
|
43
|
+
case FIO_LOG_LEVEL_WARNING: FIO_LOG_WARNING("%s", cstr); break;
|
|
44
|
+
case FIO_LOG_LEVEL_INFO: FIO_LOG_INFO("%s", cstr); break;
|
|
45
|
+
default: FIO_LOG_DEBUG2("%s", cstr); break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Shared implementation for all leveled methods.
|
|
51
|
+
*
|
|
52
|
+
* Each argument is logged as its own message. Arguments that answer `call`
|
|
53
|
+
* (e.g. Proc / lambda) are invoked and their return value is logged. If a
|
|
54
|
+
* block is given, it is called last and its return value is logged (Rack
|
|
55
|
+
* SPEC compatible logger behavior).
|
|
56
|
+
*
|
|
57
|
+
* Lazy evaluation: when the level exceeds the current verbosity, nothing is
|
|
58
|
+
* evaluated - arguments are not converted, callables are not invoked and the
|
|
59
|
+
* block is not called.
|
|
60
|
+
*/
|
|
61
|
+
static VALUE iodine_log_write(int level, int argc, VALUE *argv) {
|
|
62
|
+
if (level > FIO_LOG_LEVEL_GET())
|
|
63
|
+
return Qnil;
|
|
64
|
+
for (int i = 0; i < argc; ++i) {
|
|
65
|
+
VALUE msg = argv[i];
|
|
66
|
+
if (rb_respond_to(msg, IODINE_CALL_ID))
|
|
67
|
+
msg = rb_funcall2(msg, IODINE_CALL_ID, 0, NULL);
|
|
68
|
+
iodine_log_emit_value(level, msg);
|
|
69
|
+
}
|
|
70
|
+
if (rb_block_given_p())
|
|
71
|
+
iodine_log_emit_value(
|
|
72
|
+
level,
|
|
73
|
+
rb_funcall2(rb_block_proc(), IODINE_CALL_ID, 0, NULL));
|
|
74
|
+
return Qnil;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @!method fatal(*messages, &block)
|
|
79
|
+
* Logs each message at fatal level (level 1).
|
|
80
|
+
*
|
|
81
|
+
* Callable arguments are invoked and a block's return value is logged
|
|
82
|
+
* (evaluated only when the level is active).
|
|
83
|
+
*
|
|
84
|
+
* @param messages [Array<Object>] the messages (converted with #to_s)
|
|
85
|
+
* @return [nil]
|
|
86
|
+
*/
|
|
87
|
+
static VALUE iodine_log_fatal(int argc, VALUE *argv, VALUE self) {
|
|
88
|
+
return iodine_log_write(FIO_LOG_LEVEL_FATAL, argc, argv);
|
|
89
|
+
(void)self;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @!method error(*messages, &block)
|
|
94
|
+
* Logs each message at error level (level 2).
|
|
95
|
+
*
|
|
96
|
+
* Callable arguments are invoked and a block's return value is logged
|
|
97
|
+
* (evaluated only when the level is active).
|
|
98
|
+
*
|
|
99
|
+
* @param messages [Array<Object>] the messages (converted with #to_s)
|
|
100
|
+
* @return [nil]
|
|
101
|
+
*/
|
|
102
|
+
static VALUE iodine_log_error(int argc, VALUE *argv, VALUE self) {
|
|
103
|
+
return iodine_log_write(FIO_LOG_LEVEL_ERROR, argc, argv);
|
|
104
|
+
(void)self;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @!method warn(*messages, &block)
|
|
109
|
+
* Logs each message at warning level (level 3).
|
|
110
|
+
*
|
|
111
|
+
* Callable arguments are invoked and a block's return value is logged
|
|
112
|
+
* (evaluated only when the level is active).
|
|
113
|
+
*
|
|
114
|
+
* @param messages [Array<Object>] the messages (converted with #to_s)
|
|
115
|
+
* @return [nil]
|
|
116
|
+
*/
|
|
117
|
+
static VALUE iodine_log_warn(int argc, VALUE *argv, VALUE self) {
|
|
118
|
+
return iodine_log_write(FIO_LOG_LEVEL_WARNING, argc, argv);
|
|
119
|
+
(void)self;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @!method info(*messages, &block)
|
|
124
|
+
* Logs each message at info level (level 4).
|
|
125
|
+
*
|
|
126
|
+
* Callable arguments are invoked and a block's return value is logged
|
|
127
|
+
* (evaluated only when the level is active).
|
|
128
|
+
*
|
|
129
|
+
* @param messages [Array<Object>] the messages (converted with #to_s)
|
|
130
|
+
* @return [nil]
|
|
131
|
+
*/
|
|
132
|
+
static VALUE iodine_log_info(int argc, VALUE *argv, VALUE self) {
|
|
133
|
+
return iodine_log_write(FIO_LOG_LEVEL_INFO, argc, argv);
|
|
134
|
+
(void)self;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @!method <<(message)
|
|
139
|
+
* Alias for {#info} - logs the message at info level (level 4).
|
|
140
|
+
*
|
|
141
|
+
* @param message [Object] the message (converted with #to_s)
|
|
142
|
+
* @return [nil]
|
|
143
|
+
*/
|
|
144
|
+
static VALUE iodine_log_lshift(int argc, VALUE *argv, VALUE self) {
|
|
145
|
+
return iodine_log_write(FIO_LOG_LEVEL_INFO, argc, argv);
|
|
146
|
+
(void)self;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @!method debug(*messages, &block)
|
|
151
|
+
* Logs each message at debug level (level 5), routed through FIO_LOG_DEBUG2
|
|
152
|
+
* (the C file:line prefix is omitted, since it would point at the binding
|
|
153
|
+
* rather than the Ruby caller).
|
|
154
|
+
*
|
|
155
|
+
* Callable arguments are invoked and a block's return value is logged
|
|
156
|
+
* (evaluated only when the level is active).
|
|
157
|
+
*
|
|
158
|
+
* @param messages [Array<Object>] the messages (converted with #to_s)
|
|
159
|
+
* @return [nil]
|
|
160
|
+
*/
|
|
161
|
+
static VALUE iodine_log_debug(int argc, VALUE *argv, VALUE self) {
|
|
162
|
+
return iodine_log_write(FIO_LOG_LEVEL_DEBUG, argc, argv);
|
|
163
|
+
(void)self;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/* *****************************************************************************
|
|
167
|
+
Level helpers
|
|
168
|
+
***************************************************************************** */
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @!method level
|
|
172
|
+
* Returns the current logging level (the process-wide C STL log level).
|
|
173
|
+
*
|
|
174
|
+
* @return [Integer] the current log level (0-5)
|
|
175
|
+
*/
|
|
176
|
+
static VALUE iodine_log_level(VALUE self) {
|
|
177
|
+
return RB_INT2FIX(((long)FIO_LOG_LEVEL_GET()));
|
|
178
|
+
(void)self;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @!method level=(level)
|
|
183
|
+
* Sets the current logging level (the process-wide C STL log level).
|
|
184
|
+
*
|
|
185
|
+
* @param level [Integer, Symbol] the log level: 0-5, or one of
|
|
186
|
+
* :none, :fatal, :error, :warn, :info, :debug
|
|
187
|
+
* @return [Integer, Symbol] the given level
|
|
188
|
+
* @raise [TypeError] if level is not an Integer or Symbol
|
|
189
|
+
* @raise [ArgumentError] if the level value is unknown or out of range
|
|
190
|
+
*/
|
|
191
|
+
static VALUE iodine_log_level_set(VALUE self, VALUE level) {
|
|
192
|
+
int n;
|
|
193
|
+
if (RB_TYPE_P(level, RUBY_T_SYMBOL)) {
|
|
194
|
+
ID id = rb_sym2id(level);
|
|
195
|
+
if (id == rb_intern("none")) {
|
|
196
|
+
n = FIO_LOG_LEVEL_NONE;
|
|
197
|
+
} else if (id == rb_intern("fatal")) {
|
|
198
|
+
n = FIO_LOG_LEVEL_FATAL;
|
|
199
|
+
} else if (id == rb_intern("error")) {
|
|
200
|
+
n = FIO_LOG_LEVEL_ERROR;
|
|
201
|
+
} else if (id == rb_intern("warn") || id == rb_intern("warning")) {
|
|
202
|
+
n = FIO_LOG_LEVEL_WARNING;
|
|
203
|
+
} else if (id == rb_intern("info")) {
|
|
204
|
+
n = FIO_LOG_LEVEL_INFO;
|
|
205
|
+
} else if (id == rb_intern("debug")) {
|
|
206
|
+
n = FIO_LOG_LEVEL_DEBUG;
|
|
207
|
+
} else {
|
|
208
|
+
rb_raise(rb_eArgError,
|
|
209
|
+
"unknown log level: :%s (expected :none, :fatal, :error, "
|
|
210
|
+
":warn, :info or :debug)",
|
|
211
|
+
rb_id2name(id));
|
|
212
|
+
return Qnil;
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
rb_check_type(level, RUBY_T_FIXNUM);
|
|
216
|
+
long lng = RB_FIX2INT(level);
|
|
217
|
+
if (lng < FIO_LOG_LEVEL_NONE || lng > FIO_LOG_LEVEL_DEBUG) {
|
|
218
|
+
rb_raise(rb_eArgError, "log level must be between 0 and 5");
|
|
219
|
+
return Qnil;
|
|
220
|
+
}
|
|
221
|
+
n = (int)lng;
|
|
222
|
+
}
|
|
223
|
+
FIO_LOG_LEVEL_SET(n);
|
|
224
|
+
return level;
|
|
225
|
+
(void)self;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* *****************************************************************************
|
|
229
|
+
Initialization
|
|
230
|
+
***************************************************************************** */
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Initializes the Iodine::Logger module.
|
|
234
|
+
*/
|
|
235
|
+
static void Init_Iodine_Logger(void) {
|
|
236
|
+
iodine_rb_IODINE_LOGGER = rb_define_module_under(iodine_rb_IODINE, "Logger");
|
|
237
|
+
STORE.hold(iodine_rb_IODINE_LOGGER);
|
|
238
|
+
|
|
239
|
+
/* Log level constants (mirroring the facil.io FIO_LOG_LEVEL_* values) */
|
|
240
|
+
rb_define_const(iodine_rb_IODINE_LOGGER,
|
|
241
|
+
"NONE",
|
|
242
|
+
RB_INT2FIX(FIO_LOG_LEVEL_NONE));
|
|
243
|
+
rb_define_const(iodine_rb_IODINE_LOGGER,
|
|
244
|
+
"FATAL",
|
|
245
|
+
RB_INT2FIX(FIO_LOG_LEVEL_FATAL));
|
|
246
|
+
rb_define_const(iodine_rb_IODINE_LOGGER,
|
|
247
|
+
"ERROR",
|
|
248
|
+
RB_INT2FIX(FIO_LOG_LEVEL_ERROR));
|
|
249
|
+
rb_define_const(iodine_rb_IODINE_LOGGER,
|
|
250
|
+
"WARN",
|
|
251
|
+
RB_INT2FIX(FIO_LOG_LEVEL_WARNING));
|
|
252
|
+
rb_define_const(iodine_rb_IODINE_LOGGER,
|
|
253
|
+
"INFO",
|
|
254
|
+
RB_INT2FIX(FIO_LOG_LEVEL_INFO));
|
|
255
|
+
rb_define_const(iodine_rb_IODINE_LOGGER,
|
|
256
|
+
"DEBUG",
|
|
257
|
+
RB_INT2FIX(FIO_LOG_LEVEL_DEBUG));
|
|
258
|
+
|
|
259
|
+
/* Leveled logging methods (module functions: callable on the module and
|
|
260
|
+
* available as private instance methods when included) */
|
|
261
|
+
rb_define_module_function(iodine_rb_IODINE_LOGGER,
|
|
262
|
+
"fatal",
|
|
263
|
+
iodine_log_fatal,
|
|
264
|
+
-1);
|
|
265
|
+
rb_define_module_function(iodine_rb_IODINE_LOGGER,
|
|
266
|
+
"error",
|
|
267
|
+
iodine_log_error,
|
|
268
|
+
-1);
|
|
269
|
+
rb_define_module_function(iodine_rb_IODINE_LOGGER,
|
|
270
|
+
"warn",
|
|
271
|
+
iodine_log_warn,
|
|
272
|
+
-1);
|
|
273
|
+
rb_define_module_function(iodine_rb_IODINE_LOGGER,
|
|
274
|
+
"info",
|
|
275
|
+
iodine_log_info,
|
|
276
|
+
-1);
|
|
277
|
+
rb_define_module_function(iodine_rb_IODINE_LOGGER,
|
|
278
|
+
"debug",
|
|
279
|
+
iodine_log_debug,
|
|
280
|
+
-1);
|
|
281
|
+
rb_define_module_function(iodine_rb_IODINE_LOGGER,
|
|
282
|
+
"<<",
|
|
283
|
+
iodine_log_lshift,
|
|
284
|
+
-1);
|
|
285
|
+
|
|
286
|
+
/* Level helpers */
|
|
287
|
+
rb_define_module_function(iodine_rb_IODINE_LOGGER,
|
|
288
|
+
"level",
|
|
289
|
+
iodine_log_level,
|
|
290
|
+
0);
|
|
291
|
+
rb_define_module_function(iodine_rb_IODINE_LOGGER,
|
|
292
|
+
"level=",
|
|
293
|
+
iodine_log_level_set,
|
|
294
|
+
1);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
#endif /* H___IODINE_LOG___H */
|