Parent

Namespace

Class/Module Index

Clogger

See the README for usage instructions

Public Class Methods

new(app, :logger => $stderr, :format => string) => obj view method source

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;
}

Public Instance Methods

call(env) => [ status, headers, body ] view method source

calls the wrapped Rack application with env, returns the

status, headers, body

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 bodyclose call to the underlying body object. This is only used when Clogger is wrapping the body of a Rack response and should be automatically called by the web server.

static VALUE clogger_close(VALUE self)
{

        return rb_ensure(body_close, self, clogger_write, self);
}
each { |part| socket.write(part) } view method source

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;
}
respond_to?(:to_path) => true or false view method source
respond_to?(:close) => true

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.