steno 1.2.2-x86-mingw32

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.
Files changed (50) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE +7136 -0
  3. data/README.md +78 -0
  4. data/Rakefile +16 -0
  5. data/bin/steno-prettify +99 -0
  6. data/lib/steno.rb +133 -0
  7. data/lib/steno/codec.rb +2 -0
  8. data/lib/steno/codec/base.rb +34 -0
  9. data/lib/steno/codec/json.rb +36 -0
  10. data/lib/steno/config.rb +97 -0
  11. data/lib/steno/context.rb +59 -0
  12. data/lib/steno/core_ext.rb +11 -0
  13. data/lib/steno/errors.rb +3 -0
  14. data/lib/steno/http_handler.rb +41 -0
  15. data/lib/steno/json_prettifier.rb +131 -0
  16. data/lib/steno/log_level.rb +24 -0
  17. data/lib/steno/logger.rb +174 -0
  18. data/lib/steno/record.rb +41 -0
  19. data/lib/steno/sink.rb +6 -0
  20. data/lib/steno/sink/base.rb +38 -0
  21. data/lib/steno/sink/counter.rb +44 -0
  22. data/lib/steno/sink/eventlog.rb +46 -0
  23. data/lib/steno/sink/fluentd.rb +31 -0
  24. data/lib/steno/sink/io.rb +72 -0
  25. data/lib/steno/sink/syslog.rb +59 -0
  26. data/lib/steno/tagged_logger.rb +59 -0
  27. data/lib/steno/version.rb +3 -0
  28. data/spec/spec_helper.rb +6 -0
  29. data/spec/support/barrier.rb +22 -0
  30. data/spec/support/null_sink.rb +17 -0
  31. data/spec/support/shared_context_specs.rb +7 -0
  32. data/spec/unit/config_spec.rb +221 -0
  33. data/spec/unit/context_spec.rb +62 -0
  34. data/spec/unit/core_ext_spec.rb +38 -0
  35. data/spec/unit/http_handler_spec.rb +73 -0
  36. data/spec/unit/json_codec_spec.rb +48 -0
  37. data/spec/unit/json_prettifier_spec.rb +84 -0
  38. data/spec/unit/log_level_spec.rb +19 -0
  39. data/spec/unit/logger_spec.rb +101 -0
  40. data/spec/unit/record_spec.rb +30 -0
  41. data/spec/unit/sink/counter_spec.rb +27 -0
  42. data/spec/unit/sink/eventlog_spec.rb +41 -0
  43. data/spec/unit/sink/fluentd_spec.rb +46 -0
  44. data/spec/unit/sink/io_spec.rb +111 -0
  45. data/spec/unit/sink/syslog_spec.rb +74 -0
  46. data/spec/unit/steno_spec.rb +86 -0
  47. data/spec/unit/tagged_logger_spec.rb +33 -0
  48. data/steno-1.2.1.gem +0 -0
  49. data/steno.gemspec +41 -0
  50. metadata +224 -0
@@ -0,0 +1,41 @@
1
+ require "digest/md5"
2
+ require "thread"
3
+
4
+ module Steno
5
+ end
6
+
7
+ class Steno::Record
8
+
9
+ attr_reader :timestamp
10
+ attr_reader :message
11
+ attr_reader :log_level
12
+ attr_reader :source
13
+ attr_reader :data
14
+ attr_reader :thread_id
15
+ attr_reader :fiber_id
16
+ attr_reader :process_id
17
+ attr_reader :file
18
+ attr_reader :lineno
19
+ attr_reader :method
20
+
21
+ # @param [String] source Identifies message source.
22
+ # @param [Symbol] log_level
23
+ # @param [String] message
24
+ # @param [Array] loc Location where the record was generated.
25
+ # Format is [<filename>, <lineno>, <method>].
26
+ # @param [Hash] data User-supplied data
27
+ def initialize(source, log_level, message, loc = [], data = {})
28
+ raise "Log level must be a Symbol" unless log_level.is_a? Symbol
29
+
30
+ @timestamp = Time.now
31
+ @source = source
32
+ @log_level = log_level
33
+ @message = message.to_s
34
+ @data = {}.merge(data)
35
+ @thread_id = Thread.current.object_id
36
+ @fiber_id = Fiber.current.object_id
37
+ @process_id = Process.pid
38
+
39
+ @file, @lineno, @method = loc
40
+ end
41
+ end
data/lib/steno/sink.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "steno/sink/base"
2
+ require "steno/sink/io"
3
+ require "steno/sink/syslog"
4
+ require "steno/sink/fluentd"
5
+ require "steno/sink/counter"
6
+ require "steno/sink/eventlog"
@@ -0,0 +1,38 @@
1
+ require "rbconfig"
2
+ require "thread"
3
+
4
+ module Steno
5
+ module Sink
6
+ WINDOWS = (RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)
7
+ end
8
+ end
9
+
10
+ # Sinks represent the final destination for log records. They abstract storage
11
+ # mediums (like files) and transport layers (like sockets).
12
+ class Steno::Sink::Base
13
+
14
+ attr_accessor :codec
15
+
16
+ # @param [Steno::Codec::Base] formatter Transforms log records to their
17
+ # raw, string-based representation that will be written to the underlying
18
+ # sink.
19
+ def initialize(codec = nil)
20
+ @codec = codec
21
+ end
22
+
23
+ # Adds a record to be flushed at a later time.
24
+ #
25
+ # @param [Hash] record
26
+ #
27
+ # @return [nil]
28
+ def add_record(record)
29
+ raise NotImplementedError
30
+ end
31
+
32
+ # Flushes any buffered records.
33
+ #
34
+ # @return [nil]
35
+ def flush
36
+ raise NotImplementedError
37
+ end
38
+ end
@@ -0,0 +1,44 @@
1
+ require "steno/sink/base"
2
+
3
+ module Steno
4
+ module Sink
5
+ end
6
+ end
7
+
8
+ class Steno::Sink::Counter < Steno::Sink::Base
9
+
10
+ def initialize
11
+ # Map of String -> numeric count
12
+ @counts = {}
13
+ @mutex = Mutex.new
14
+ end
15
+
16
+ def add_record(record)
17
+ level = record.log_level.to_s
18
+
19
+ @mutex.synchronize do
20
+ unless @counts[level]
21
+ @counts[level] = 0
22
+ end
23
+ @counts[level] += 1
24
+ end
25
+ end
26
+
27
+ def flush
28
+ end
29
+
30
+ def to_json
31
+ hash = {}
32
+ @mutex.synchronize do
33
+ Steno::Logger::LEVELS.keys.each do |level_name|
34
+ hash[level_name] = @counts.fetch(level_name.to_s, 0)
35
+ end
36
+ end
37
+ Yajl::Encoder.encode(hash)
38
+ end
39
+
40
+ # Provide a map of string level -> count. This is thread-safe, the return value is a copy.
41
+ def counts
42
+ @mutex.synchronize { @counts.dup }
43
+ end
44
+ end
@@ -0,0 +1,46 @@
1
+ if Steno::Sink::WINDOWS
2
+ require "steno/sink/base"
3
+
4
+ require "singleton"
5
+ require "thread"
6
+ require 'win32/eventlog'
7
+
8
+ class Steno::Sink::Eventlog < Steno::Sink::Base
9
+ include Singleton
10
+
11
+ LOG_LEVEL_MAP = {
12
+ :fatal => Win32::EventLog::ERROR,
13
+ :error => Win32::EventLog::ERROR,
14
+ :warn => Win32::EventLog::WARN,
15
+ :info => Win32::EventLog::INFO,
16
+ :debug => Win32::EventLog::INFO,
17
+ :debug1 => Win32::EventLog::INFO,
18
+ :debug2 => Win32::EventLog::INFO,
19
+ }
20
+
21
+ def initialize
22
+ super
23
+ @eventlog = nil
24
+ end
25
+
26
+ def open()
27
+ @eventlog = Win32::EventLog::open('Application')
28
+ end
29
+
30
+ def add_record(record)
31
+ msg = @codec.encode_record(record)
32
+ pri = LOG_LEVEL_MAP[record.log_level]
33
+
34
+ @eventlog.report_event(
35
+ :source => 'CloudFoundry',
36
+ :event_type => pri,
37
+ :data => msg
38
+ )
39
+ end
40
+
41
+ def flush
42
+ nil
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,31 @@
1
+ require 'fluent-logger'
2
+ #
3
+ # Steno sink implementation for Fluentd
4
+ #
5
+ # See fluentd at http://fluentd.org/
6
+ # and fluent-logger at https://github.com/fluent/fluent-logger-ruby
7
+ #
8
+ class Steno::Sink::Fluentd < Steno::Sink::Base
9
+
10
+ # @param [Hash] opts Key :tag_prefix tag prefix of fluent logs (default: steno)
11
+ # Key :host fluentd host (default: 127.0.0.1)
12
+ # Key :port fluentd port (deafult: 24224)
13
+ # Key :buffer_limit buffer limit of fluent-logger
14
+ def initialize(opts = {})
15
+ super
16
+
17
+ @fluentd = Fluent::Logger::FluentLogger.new(opts[:tag_prefix] || "steno",
18
+ :host => opts[:host] || "127.0.0.1",
19
+ :port => opts[:port] || 24224,
20
+ :buffer_limit => opts[:buffer_limit] || Fluent::Logger::FluentLogger::BUFFER_LIMIT)
21
+ @io_lock = Mutex.new
22
+ end
23
+
24
+ def add_record(record)
25
+ @fluentd.post(record.source, record)
26
+ end
27
+
28
+ def flush
29
+ nil
30
+ end
31
+ end
@@ -0,0 +1,72 @@
1
+ require "steno/sink/base"
2
+
3
+ module Steno
4
+ module Sink
5
+ end
6
+ end
7
+
8
+ class Steno::Sink::IO < Steno::Sink::Base
9
+ class << self
10
+ # Returns a new sink configured to append to the file at path.
11
+ #
12
+ # @param [String] path
13
+ # @param [Hash] If the key :autoflush is set to true, encoded records
14
+ # will not be buffered by Ruby. The key :max_retries
15
+ # is forwarded to Steno::Sink::IO object during creation.
16
+ # @return [Steno::Sink::IO]
17
+ def for_file(path, opts = {})
18
+ autoflush = true
19
+ if opts.include?(:autoflush)
20
+ autoflush = opts[:autoflush]
21
+ end
22
+
23
+ io = File.open(path, "a+")
24
+
25
+ io.sync = autoflush
26
+
27
+ new(io, :max_retries => opts[:max_retries])
28
+ end
29
+ end
30
+
31
+ attr_reader :max_retries
32
+
33
+ # @param [IO] io The IO object that will be written to
34
+ # @param [Hash] opts Key :codec is used to specify a codec inheriting from
35
+ # Steno::Codec::Base.
36
+ # Key :max_retries takes an integer value which specifies
37
+ # the number of times the write operation can be retried
38
+ # when IOError is raised while writing a record.
39
+ def initialize(io, opts = {})
40
+ super(opts[:codec])
41
+
42
+ @max_retries = opts[:max_retries] || -1
43
+ @io_lock = Mutex.new
44
+ @io = io
45
+ end
46
+
47
+ def add_record(record)
48
+ bytes = @codec.encode_record(record)
49
+
50
+ @io_lock.synchronize do
51
+ retries = 0
52
+ begin
53
+ @io.write(bytes)
54
+ rescue IOError => e
55
+ if retries < @max_retries
56
+ retries += 1
57
+ retry
58
+ else
59
+ raise e
60
+ end
61
+ end
62
+ end
63
+
64
+ nil
65
+ end
66
+
67
+ def flush
68
+ @io_lock.synchronize { @io.flush }
69
+
70
+ nil
71
+ end
72
+ end
@@ -0,0 +1,59 @@
1
+ unless Steno::Sink::WINDOWS
2
+ require "steno/sink/base"
3
+
4
+ require "singleton"
5
+ require "thread"
6
+ require "syslog"
7
+
8
+ class Steno::Sink::Syslog < Steno::Sink::Base
9
+ include Singleton
10
+
11
+ MAX_MESSAGE_SIZE = 1024 * 3
12
+
13
+ LOG_LEVEL_MAP = {
14
+ :fatal => Syslog::LOG_CRIT,
15
+ :error => Syslog::LOG_ERR,
16
+ :warn => Syslog::LOG_WARNING,
17
+ :info => Syslog::LOG_INFO,
18
+ :debug => Syslog::LOG_DEBUG,
19
+ :debug1 => Syslog::LOG_DEBUG,
20
+ :debug2 => Syslog::LOG_DEBUG,
21
+ }
22
+
23
+ def initialize
24
+ super
25
+
26
+ @syslog = nil
27
+ @syslog_lock = Mutex.new
28
+ end
29
+
30
+ def open(identity)
31
+ @identity = identity
32
+ @syslog = Syslog.open(@identity, Syslog::LOG_PID, Syslog::LOG_USER)
33
+ end
34
+
35
+ def add_record(record)
36
+ record = truncate_record(record)
37
+ msg = @codec.encode_record(record)
38
+ pri = LOG_LEVEL_MAP[record.log_level]
39
+ @syslog_lock.synchronize { @syslog.log(pri, "%s", msg) }
40
+ end
41
+
42
+ def flush
43
+ nil
44
+ end
45
+
46
+ private
47
+
48
+ def truncate_record(record)
49
+ return record if record.message.size <= MAX_MESSAGE_SIZE
50
+
51
+ truncated = record.message.slice(0..(MAX_MESSAGE_SIZE - 1))
52
+ truncated << "..."
53
+ Steno::Record.new(record.source, record.log_level,
54
+ truncated,
55
+ [record.file, record.lineno, record.method],
56
+ record.data)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,59 @@
1
+ require "steno/logger"
2
+
3
+ module Steno
4
+ end
5
+
6
+ # Provides a proxy that allows persistent user data
7
+ class Steno::TaggedLogger
8
+
9
+ attr_reader :proxied_logger
10
+ attr_accessor :user_data
11
+
12
+ class << self
13
+ # The following helpers are used to create a new scope for binding the log
14
+ # level.
15
+
16
+ def define_log_method(name)
17
+ define_method(name) { |*args, &blk| log(name, *args, &blk) }
18
+ end
19
+
20
+ def define_logf_method(name)
21
+ define_method(name.to_s + "f") { |fmt, *args| log(name, fmt % args) }
22
+ end
23
+ end
24
+
25
+ Steno::Logger::LEVELS.each do |name, _|
26
+ # Define #debug, for example
27
+ define_log_method(name)
28
+
29
+ # Define #debugf, for example
30
+ define_logf_method(name)
31
+ end
32
+
33
+ def initialize(proxied_logger, user_data = {})
34
+ @proxied_logger = proxied_logger
35
+ @user_data = user_data
36
+ end
37
+
38
+ def method_missing(method, *args, &blk)
39
+ @proxied_logger.send(method, *args, &blk)
40
+ end
41
+
42
+ # @see Steno::Logger#log
43
+ def log(level_name, message = nil, user_data = nil, &blk)
44
+ ud = @user_data.merge(user_data || {})
45
+
46
+ @proxied_logger.log(level_name, message, ud, &blk)
47
+ end
48
+
49
+ # @see Steno::Logger#log_exception
50
+ def log_exception(ex, user_data = {})
51
+ ud = @user_data.merge(user_data || {})
52
+
53
+ @proxied_logger.log_exception(ex, ud)
54
+ end
55
+
56
+ def tag(new_user_data = {})
57
+ Steno::TaggedLogger.new(proxied_logger, user_data.merge(new_user_data))
58
+ end
59
+ end
@@ -0,0 +1,3 @@
1
+ module Steno
2
+ VERSION = "1.2.2"
3
+ end
@@ -0,0 +1,6 @@
1
+ require "rack/test"
2
+ require "rspec"
3
+
4
+ require "steno"
5
+
6
+ Dir["./spec/support/**/*.rb"].each { |file| require file }
@@ -0,0 +1,22 @@
1
+ require "thread"
2
+
3
+ class Barrier
4
+ def initialize
5
+ @lock = Mutex.new
6
+ @cvar = ConditionVariable.new
7
+ @done = false
8
+ end
9
+
10
+ def release
11
+ @lock.synchronize do
12
+ @done = true
13
+ @cvar.broadcast
14
+ end
15
+ end
16
+
17
+ def wait
18
+ @lock.synchronize do
19
+ @cvar.wait(@lock) if !@done
20
+ end
21
+ end
22
+ end