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,59 @@
1
+ require "fiber"
2
+ require "thread"
3
+
4
+ class Fiber
5
+ def __steno_context_data__
6
+ @__steno_context_data__ ||= {}
7
+ end
8
+
9
+ def __steno_clear_context_data__
10
+ @__steno_context_data__ = {}
11
+ end
12
+ end
13
+
14
+ module Steno
15
+ end
16
+
17
+ module Steno::Context
18
+ class Base
19
+ def data
20
+ raise NotImplementedError
21
+ end
22
+
23
+ def clear
24
+ raise NotImplementedError
25
+ end
26
+ end
27
+
28
+ class Null < Base
29
+ def data
30
+ {}
31
+ end
32
+
33
+ def clear
34
+ nil
35
+ end
36
+ end
37
+
38
+ class ThreadLocal < Base
39
+ THREAD_LOCAL_KEY = "__steno_locals__"
40
+
41
+ def data
42
+ Thread.current[THREAD_LOCAL_KEY] ||= {}
43
+ end
44
+
45
+ def clear
46
+ Thread.current[THREAD_LOCAL_KEY] = {}
47
+ end
48
+ end
49
+
50
+ class FiberLocal < Base
51
+ def data
52
+ Fiber.current.__steno_context_data__
53
+ end
54
+
55
+ def clear
56
+ Fiber.current.__steno_clear_context_data__
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,11 @@
1
+ class Module
2
+ def logger
3
+ Steno.logger(name)
4
+ end
5
+ end
6
+
7
+ class Object
8
+ def logger
9
+ self.class.logger
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module Steno
2
+ class Error < StandardError; end
3
+ end
@@ -0,0 +1,41 @@
1
+ require "steno"
2
+
3
+ require "grape"
4
+
5
+ module Steno
6
+ end
7
+
8
+ class Steno::HttpHandler < Grape::API
9
+ format :json
10
+
11
+ resource :loggers do
12
+ get :levels do
13
+ Steno.logger_level_snapshot
14
+ end
15
+
16
+ put :levels do
17
+ missing = [:regexp, :level].select { |p| !params.key?(p) }.map(&:to_s)
18
+
19
+ if !missing.empty?
20
+ error!("Missing query parameters: #{missing}", 400)
21
+ end
22
+
23
+ regexp = nil
24
+ begin
25
+ regexp = Regexp.new(params[:regexp])
26
+ rescue => e
27
+ error!("Invalid regexp", 400)
28
+ end
29
+
30
+ level = params[:level].to_sym
31
+ if !Steno::Logger::LEVELS.key?(level)
32
+ levels = Steno::Logger::LEVELS.keys.map(&:to_s)
33
+ error!("Unknown level: #{level}. Supported levels are: #{levels}", 400)
34
+ end
35
+
36
+ Steno.set_logger_regexp(regexp, level)
37
+
38
+ "ok"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,131 @@
1
+ require "digest/md5"
2
+ require "set"
3
+ require "yajl"
4
+
5
+ module Steno
6
+ end
7
+
8
+ class Steno::JsonPrettifier
9
+ FIELD_ORDER = %w[
10
+ timestamp
11
+ source
12
+ process_id
13
+ thread_id
14
+ fiber_id
15
+ location
16
+ data
17
+ log_level
18
+ message
19
+ ]
20
+
21
+ MIN_COL_WIDTH = 14
22
+
23
+ class ParseError < StandardError
24
+ end
25
+
26
+ def initialize(excluded_fields = [])
27
+ @time_format = "%Y-%m-%d %H:%M:%S.%6N"
28
+ @excluded_fields = Set.new(excluded_fields)
29
+ @max_src_len = MIN_COL_WIDTH
30
+ end
31
+
32
+ def prettify_line(line)
33
+ begin
34
+ json_record = Yajl::Parser.parse(line)
35
+ rescue Yajl::ParseError => e
36
+ raise ParseError, e.to_s
37
+ end
38
+
39
+ format_record(json_record)
40
+ end
41
+
42
+ protected
43
+
44
+ def format_record(record)
45
+ record ||= {}
46
+ fields = []
47
+
48
+ FIELD_ORDER.each do |field_name|
49
+ next if @excluded_fields.include?(field_name)
50
+
51
+ exists = nil
52
+ pred_meth = "check_#{field_name}".to_sym
53
+ if respond_to?(pred_meth)
54
+ exists = send(pred_meth, record)
55
+ elsif record.respond_to?(:has_key?)
56
+ exists = record.has_key?(field_name)
57
+ else
58
+ msg = "Expected the record to be a hash, but received: #{record.class}."
59
+ raise ParseError, msg
60
+ end
61
+
62
+ if exists
63
+ fields << send("format_#{field_name}".to_sym, record)
64
+ else
65
+ fields << "-"
66
+ end
67
+ end
68
+
69
+ fields.join(" ") + "\n"
70
+ end
71
+
72
+ def format_timestamp(record)
73
+ Time.at(record["timestamp"]).strftime(@time_format)
74
+ end
75
+
76
+ def format_source(record)
77
+ @max_src_len = [@max_src_len, record["source"].length].max
78
+ record["source"].ljust(@max_src_len)
79
+ end
80
+
81
+ def format_process_id(record)
82
+ "pid=%-5s" % [record["process_id"]]
83
+ end
84
+
85
+ def format_thread_id(record)
86
+ "tid=%s" % [shortid(record["thread_id"])]
87
+ end
88
+
89
+ def format_fiber_id(record)
90
+ "fid=%s" % [shortid(record["fiber_id"])]
91
+ end
92
+
93
+ def check_location(record)
94
+ %w[file lineno method].reduce(true) { |ok, k| ok && record.has_key?(k) }
95
+ end
96
+
97
+ def format_location(record)
98
+ parts = record["file"].split("/")
99
+
100
+ trimmed_filename = nil
101
+ if parts.size == 1
102
+ trimmed_filename = parts[0]
103
+ else
104
+ trimmed_filename = parts.slice(-2, 2).join("/")
105
+ end
106
+
107
+ "%s/%s:%s" % [trimmed_filename, record["method"], record["lineno"]]
108
+ end
109
+
110
+ def check_data(record)
111
+ record["data"].is_a?(Hash)
112
+ end
113
+
114
+ def format_data(record)
115
+ record["data"].map { |k, v| "#{k}=#{v}" }.join(",")
116
+ end
117
+
118
+ def format_log_level(record)
119
+ "%7s" % [record["log_level"].upcase]
120
+ end
121
+
122
+ def format_message(record)
123
+ "-- %s" % [record["message"]]
124
+ end
125
+
126
+ def shortid(data)
127
+ return "-" if data.nil?
128
+ digest = Digest::MD5.hexdigest(data.to_s)
129
+ digest[0, 4]
130
+ end
131
+ end
@@ -0,0 +1,24 @@
1
+ module Steno
2
+ end
3
+
4
+ class Steno::LogLevel
5
+ include Comparable
6
+
7
+ attr_reader :name
8
+ attr_reader :priority
9
+
10
+ # @param [String] name "info", "debug", etc.
11
+ # @param [Integer] priority "info" > "debug", etc.
12
+ def initialize(name, priority)
13
+ @name = name
14
+ @priority = priority
15
+ end
16
+
17
+ def to_s
18
+ @name.to_s
19
+ end
20
+
21
+ def <=>(other)
22
+ @priority <=> other.priority
23
+ end
24
+ end
@@ -0,0 +1,174 @@
1
+ require "thread"
2
+
3
+ require "steno/errors"
4
+ require "steno/log_level"
5
+
6
+ module Steno
7
+ end
8
+
9
+ class Steno::Logger
10
+ LEVELS = {
11
+ :off => Steno::LogLevel.new(:off, 0),
12
+ :fatal => Steno::LogLevel.new(:fatal, 1),
13
+ :error => Steno::LogLevel.new(:error, 5),
14
+ :warn => Steno::LogLevel.new(:warn, 10),
15
+ :info => Steno::LogLevel.new(:info, 15),
16
+ :debug => Steno::LogLevel.new(:debug, 16),
17
+ :debug1 => Steno::LogLevel.new(:debug1, 17),
18
+ :debug2 => Steno::LogLevel.new(:debug2, 18),
19
+ :all => Steno::LogLevel.new(:all, 30),
20
+ }
21
+
22
+ class << self
23
+ # The following helpers are used to create a new scope for binding the log
24
+ # level.
25
+
26
+ def define_log_method(name)
27
+ define_method(name) { |*args, &blk| log(name, *args, &blk) }
28
+ end
29
+
30
+ def define_logf_method(name)
31
+ define_method(name.to_s + "f") { |fmt, *args| log(name, fmt % args) }
32
+ end
33
+
34
+ def define_level_active_predicate(name)
35
+ define_method(name.to_s + "?") { level_active?(name) }
36
+ end
37
+
38
+ def lookup_level(name)
39
+ level = LEVELS[name]
40
+
41
+ if level.nil?
42
+ raise Steno::Error.new("Unknown level: #{name}")
43
+ end
44
+
45
+ level
46
+ end
47
+ end
48
+
49
+ # This is magic, however, it's vastly simpler than declaring each method
50
+ # manually.
51
+ LEVELS.each do |name, _|
52
+ # Define #debug, for example
53
+ define_log_method(name)
54
+
55
+ # Define #debugf, for example
56
+ define_logf_method(name)
57
+
58
+ # Define #debug?, for example. These are provided to ensure compatibility
59
+ # with Ruby's standard library Logger class.
60
+ define_level_active_predicate(name)
61
+ end
62
+
63
+ attr_reader :name
64
+
65
+ # @param [String] name The logger name.
66
+ # @param [Array<Steno::Sink::Base>] sinks
67
+ # @param [Hash] opts
68
+ # @option opts [Symbol] :level The minimum level for which this logger will
69
+ # emit log records. Defaults to :info.
70
+ # @option opts [Steno::Context] :context
71
+ def initialize(name, sinks, opts = {})
72
+ @name = name
73
+ @min_level = self.class.lookup_level(opts[:level] || :info)
74
+ @min_level_lock = Mutex.new
75
+ @sinks = sinks
76
+ @context = opts[:context] || Steno::Context::Null.new
77
+ end
78
+
79
+ # Sets the minimum level for which records will be added to sinks.
80
+ #
81
+ # @param [Symbol] level_name The level name
82
+ #
83
+ # @return [nil]
84
+ def level=(level_name)
85
+ level = self.class.lookup_level(level_name)
86
+
87
+ @min_level_lock.synchronize { @min_level = level }
88
+
89
+ nil
90
+ end
91
+
92
+ # Returns the name of the current log level
93
+ #
94
+ # @return [Symbol]
95
+ def level
96
+ @min_level_lock.synchronize { @min_level.name }
97
+ end
98
+
99
+ # Returns whether or not records for the given level would be forwarded to
100
+ # sinks.
101
+ #
102
+ # @param [Symbol] level_name
103
+ #
104
+ # @return [true || false]
105
+ def level_active?(level_name)
106
+ level = self.class.lookup_level(level_name)
107
+ @min_level_lock.synchronize { level <= @min_level }
108
+ end
109
+
110
+ # Convenience method for logging an exception, along with its backtrace.
111
+ #
112
+ # @param [Exception] ex
113
+
114
+ # @return [nil]
115
+ def log_exception(ex, user_data = {})
116
+ warn("Caught exception: #{ex}", user_data.merge(:backtrace => ex.backtrace))
117
+ end
118
+
119
+ # Adds a record to the configured sinks.
120
+ #
121
+ # @param [Symbol] level_name The level associated with the record
122
+ # @param [String] message
123
+ # @param [Hash] user_data
124
+ #
125
+ # @return [nil]
126
+ def log(level_name, message = nil, user_data = nil, &blk)
127
+ return unless level_active?(level_name)
128
+
129
+ message = yield if block_given?
130
+
131
+ callstack = caller
132
+ loc = parse_record_loc(callstack)
133
+
134
+ data = @context.data.merge(user_data || {})
135
+
136
+ record = Steno::Record.new(@name, level_name, message, loc, data)
137
+
138
+ @sinks.each { |sink| sink.add_record(record) }
139
+
140
+ nil
141
+ end
142
+
143
+ # Returns a proxy that will emit the supplied user data along with each
144
+ # log record.
145
+ #
146
+ # @param [Hash] user_data
147
+ #
148
+ # @return [Steno::TaggedLogger]
149
+ def tag(user_data = {})
150
+ Steno::TaggedLogger.new(self, user_data)
151
+ end
152
+
153
+ private
154
+
155
+ def parse_record_loc(callstack)
156
+ file, lineno, method = nil, nil, nil
157
+
158
+ callstack.each do |frame|
159
+ next if frame =~ /logger\.rb/
160
+
161
+ file, lineno, method = frame.split(":")
162
+
163
+ lineno = lineno.to_i
164
+
165
+ if method =~ /in `([^']+)/
166
+ method = $1
167
+ end
168
+
169
+ break
170
+ end
171
+
172
+ [file, lineno, method]
173
+ end
174
+ end