Object
See the README for usage instructions
Creates a new Clogger object that wraps app. :logger may be any object that responds to the “<<” method with a string argument. Instead of :logger, :path may be specified to be a :path of a File that will be opened in append mode.
static VALUE clogger_init(int argc, VALUE *argv, VALUE self)
{
struct clogger *c = clogger_get(self);
VALUE o = Qnil;
VALUE fmt = rb_const_get(mFormat, rb_intern("Common"));
rb_scan_args(argc, argv, "11", &c->app, &o);
c->fd = -1;
c->logger = Qnil;
c->reentrant = -1; /* auto-detect */
if (TYPE(o) == T_HASH) {
VALUE tmp;
tmp = rb_hash_aref(o, ID2SYM(rb_intern("path")));
c->logger = rb_hash_aref(o, ID2SYM(rb_intern("logger")));
init_logger(c, tmp);
tmp = rb_hash_aref(o, ID2SYM(rb_intern("format")));
if (!NIL_P(tmp))
fmt = tmp;
tmp = rb_hash_aref(o, ID2SYM(rb_intern("reentrant")));
switch (TYPE(tmp)) {
case T_TRUE:
c->reentrant = 1;
break;
case T_FALSE:
c->reentrant = 0;
case T_NIL:
break;
default:
rb_raise(rb_eArgError, ":reentrant must be boolean");
}
}
init_buffers(c);
c->fmt_ops = rb_funcall(self, rb_intern("compile_format"), 2, fmt, o);
if (Qtrue == rb_funcall(self, rb_intern("need_response_headers?"),
1, c->fmt_ops))
c->need_resp = 1;
if (Qtrue == rb_funcall(self, rb_intern("need_wrap_body?"),
1, c->fmt_ops))
c->wrap_body = 1;
return self;
}
calls the wrapped Rack application with env, returns the
tuplet required by Rack.
static VALUE clogger_call(VALUE self, VALUE env)
{
struct clogger *c = clogger_get(self);
VALUE rv;
env = rb_check_convert_type(env, T_HASH, "Hash", "to_hash");
if (c->wrap_body) {
/* XXX: we assume the existence of the GVL here: */
if (c->reentrant < 0) {
VALUE tmp = rb_hash_aref(env, g_rack_multithread);
c->reentrant = Qfalse == tmp ? 0 : 1;
}
if (c->reentrant) {
self = rb_obj_dup(self);
c = clogger_get(self);
}
rv = ccall(c, env);
assert(!OBJ_FROZEN(rv) && "frozen response array");
rb_ary_store(rv, 2, self);
return rv;
}
rv = ccall(c, env);
cwrite(c);
return rv;
}
Delegates the bodyeach call to the underlying body object while tracking the number of bytes yielded. This will log the request.
static VALUE clogger_each(VALUE self)
{
struct clogger *c = clogger_get(self);
rb_need_block();
c->body_bytes_sent = 0;
rb_iterate(rb_each, c->body, body_iter_i, self);
return self;
}
used to delegate :to_path checks for Rack webservers that optimize static file serving
static VALUE respond_to(VALUE self, VALUE method)
{
struct clogger *c = clogger_get(self);
ID id = rb_to_id(method);
if (close_id == id)
return Qtrue;
return rb_respond_to(c->body, id);
}
used to proxy :to_io method calls to the wrapped response body.
static VALUE to_io(VALUE self)
{
struct clogger *c = clogger_get(self);
struct stat sb;
VALUE io = rb_convert_type(c->body, T_FILE, "IO", "to_io");
if (fstat(my_fileno(io), &sb) == 0)
c->body_bytes_sent = sb.st_size;
return io;
}
used to proxy :to_path method calls to the wrapped response body.
static VALUE to_path(VALUE self)
{
struct clogger *c = clogger_get(self);
struct stat sb;
int rv;
VALUE path = rb_funcall(c->body, to_path_id, 0);
/* try to avoid an extra path lookup */
if (rb_respond_to(c->body, to_io_id)) {
rv = fstat(my_fileno(c->body), &sb);
} else {
const char *cpath = StringValueCStr(path);
unsigned devfd;
/*
* Rainbows! can use "/dev/fd/%u" in to_path output to avoid
* extra open() syscalls, too.
*/
if (sscanf(cpath, "/dev/fd/%u", &devfd) == 1)
rv = fstat((int)devfd, &sb);
else
rv = stat(cpath, &sb);
}
/*
* calling this method implies the web server will bypass
* the each method where body_bytes_sent is calculated,
* so we stat and set that value here.
*/
c->body_bytes_sent = rv == 0 ? sb.st_size : 0;
return path;
}
Originally generated with the Darkfish Rdoc Generator 2, modified by wrongdoc.