Class: Clogger

Inherits:
Object
  • Object
show all
Defined in:
lib/clogger.rb,
lib/clogger/pure.rb,
lib/clogger/format.rb,
ext/clogger_ext/clogger.c

Overview

Not at all optimized for performance, this was written based on the original C extension code so it’s not very Ruby-ish…

Defined Under Namespace

Modules: Format

Constant Summary collapse

OP_LITERAL =

:stopdoc:

0
OP_REQUEST =
1
OP_RESPONSE =
2
OP_SPECIAL =
3
OP_EVAL =
4
OP_TIME_LOCAL =
5
OP_TIME_UTC =
6
OP_REQUEST_TIME =
7
OP_TIME =
8
9
ALIASES =

support nginx variables that are less customizable than our own

{
  '$request_time' => '$request_time{3}',
  '$msec' => '$time{3}',
  '$usec' => '$time{6}',
  '$http_content_length' => '$content_length',
  '$http_content_type' => '$content_type',
}
SPECIAL_VARS =
{
  :body_bytes_sent => 0,
  :status => 1,
  :request => 2, # REQUEST_METHOD PATH_INFO?QUERY_STRING HTTP_VERSION
  :request_length => 3, # env['rack.input'].size
  :response_length => 4, # like body_bytes_sent, except "-" instead of "0"
  :ip => 5, # HTTP_X_FORWARDED_FOR || REMOTE_ADDR || -
  :pid => 6, # getpid()
  :request_uri => 7,
  :time_iso8601 => 8,
  :time_local => 9,
  :time_utc => 10,
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#new(app, : logger) ⇒ Object

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.



768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
# File 'ext/clogger_ext/clogger.c', line 768

def initialize(app, opts = {})
  # trigger autoload to avoid thread-safety issues later on
  Rack::Utils::HeaderHash

  @app = app
  @logger = opts[:logger]
  path = opts[:path]
  path && @logger and
    raise ArgumentError, ":logger and :path are independent"
  path and @logger = File.open(path, "ab")

  @logger.sync = true if @logger.respond_to?(:sync=)
  @fmt_ops = compile_format(opts[:format] || Format::Common, opts)
  @wrap_body = need_wrap_body?(@fmt_ops)
  @reentrant = opts[:reentrant]
  @need_resp = need_response_headers?(@fmt_ops)
  @body_bytes_sent = 0
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(*args, &block) ⇒ Object (private)



150
151
152
# File 'lib/clogger.rb', line 150

def method_missing(*args, &block)
  body.__send__(*args, &block)
end

Instance Attribute Details

#bodyObject

:nodoc:



1051
1052
1053
# File 'ext/clogger_ext/clogger.c', line 1051

def body
  @body
end

#body_bytes_sent=(value) ⇒ Object (writeonly)

Sets the attribute body_bytes_sent

Parameters:

  • value

    the value to set the attribute body_bytes_sent to.



9
10
11
# File 'lib/clogger/pure.rb', line 9

def body_bytes_sent=(value)
  @body_bytes_sent = value
end

#envObject

Returns the value of attribute env.



8
9
10
# File 'lib/clogger/pure.rb', line 8

def env
  @env
end

#headersObject

Returns the value of attribute headers.



8
9
10
# File 'lib/clogger/pure.rb', line 8

def headers
  @headers
end

#start=(value) ⇒ Object (writeonly)

Sets the attribute start

Parameters:

  • value

    the value to set the attribute start to.



9
10
11
# File 'lib/clogger/pure.rb', line 9

def start=(value)
  @start = value
end

#statusObject

Returns the value of attribute status.



8
9
10
# File 'lib/clogger/pure.rb', line 8

def status
  @status
end

Instance Method Details

#call(env) ⇒ Array

calls the wrapped Rack application with env, returns the

status, headers, body

tuplet required by Rack.

Returns:

  • (Array)


919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
# File 'ext/clogger_ext/clogger.c', line 919

def call(env)
  start = mono_now
  resp = @app.call(env)
  unless resp.instance_of?(Array) && resp.size == 3
    log(env, 500, {}, start)
    raise TypeError, "app response not a 3 element Array: #{resp.inspect}"
  end
  status, headers, body = resp
  headers = Rack::Utils::HeaderHash.new(headers) if @need_resp
  if @wrap_body
    @reentrant = env['rack.multithread'] if @reentrant.nil?
    wbody = @reentrant ? self.dup : self
    wbody.start = start
    wbody.env = env
    wbody.status = status
    wbody.headers = headers
    wbody.body = body
    return [ status, headers, wbody ]
  end
  log(env, status, headers, start)
  [ status, headers, body ]
end

#closeObject

Delegates the body#close 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.



863
864
865
866
867
# File 'ext/clogger_ext/clogger.c', line 863

def close
  @body.close if @body.respond_to?(:close)
ensure
  log(@env, @status, @headers)
end

#each {|part| ... } ⇒ Object

Delegates the body#each call to the underlying body object while tracking the number of bytes yielded. This will log the request.

Yields:

  • (part)


844
845
846
847
848
849
850
851
# File 'ext/clogger_ext/clogger.c', line 844

def each
  @body_bytes_sent = 0
  @body.each do |part|
    @body_bytes_sent += part.bytesize
    yield part
  end
  self
end

#filenoObject

:nodoc:



870
871
872
# File 'ext/clogger_ext/clogger.c', line 870

def fileno
  @logger.respond_to?(:fileno) ? @logger.fileno : nil
end

#initialize_copy(orig) ⇒ Object

:nodoc:



971
972
973
974
975
976
977
978
979
980
981
# File 'ext/clogger_ext/clogger.c', line 971

static VALUE clogger_init_copy(VALUE clone, VALUE orig)
{
	struct clogger *a = clogger_get(orig);
	struct clogger *b = clogger_get(clone);

	memcpy(b, a, sizeof(struct clogger));
	init_buffers(b);
	duplicate_buffers(b->fmt_ops);

	return clone;
}

#reentrant?Boolean

:nodoc:

Returns:

  • (Boolean)


302
303
304
# File 'ext/clogger_ext/clogger.c', line 302

def reentrant?
  @reentrant
end

#respond_to?(: to_path) ⇒ Boolean #respond_to?(: close) ⇒ true

used to delegate :to_path checks for Rack webservers that optimize static file serving

Overloads:

  • #respond_to?(: to_path) ⇒ Boolean

    Returns:

    • (Boolean)
  • #respond_to?(: close) ⇒ true

    Returns:

    • (true)


998
999
1000
# File 'ext/clogger_ext/clogger.c', line 998

def respond_to?(method, include_all=false)
  :close == method.to_sym || @body.respond_to?(method, include_all)
end

#to_pathObject

used to proxy :to_path method calls to the wrapped response body.



1023
1024
1025
1026
1027
# File 'ext/clogger_ext/clogger.c', line 1023

def to_path
  rv = @body.to_path
  @body_bytes_sent = File.size(rv)
  rv
end

#wrap_body?Boolean

:nodoc:

Returns:

  • (Boolean)


308
309
310
# File 'ext/clogger_ext/clogger.c', line 308

def wrap_body?
  @wrap_body
end