termite 0.0.10 → 0.0.20

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.
data/README.md CHANGED
@@ -20,9 +20,10 @@ your Gemfile or on your gem command line.
20
20
  Logging Dynamically
21
21
  ===================
22
22
 
23
- Create a logger with something like:
23
+ Create a logger with something like one of these:
24
24
 
25
25
  @logger = Termite::Logger.new
26
+ @logger = Termite::Logger.new :component => "MyLibrary"
26
27
 
27
28
  Then use it like a regular logger, possibly with options:
28
29
 
@@ -34,38 +35,54 @@ You can also pass in JSON data after your message and before your options:
34
35
  @logger.fatal("Pain and misery!", { :where_it_hurts => "elbow" }, :component => "WhinyLib")
35
36
  @logger.info("I ache", {:where_it_hurts => "kidney"}, :application => "NotMe", :component => "StoicLib")
36
37
 
37
- Termite also supports full Ruby Logger initialize parameters for backward compatibility:
38
+ Termite also supports full Ruby Logger initialize parameters for
39
+ backward compatibility:
38
40
 
39
41
  @logger = Termite::Logger.new("/var/lib/daily_termite_logs", "daily")
40
42
  @logger = Termite::Logger.new("/tmp/rotatable.txt", 15, 1024000) # Up to 15 logs of size 1024000
41
43
 
44
+ You can also use all the standard methods of Ruby logging:
45
+
46
+ @logger.log(Logger::INFO, "I feel Ruby-compatible")
47
+ @logger << "This message gets logged as INFO"
48
+
49
+ Similarly, when using a file logger, the output should be very similar
50
+ to what you'd get from a Ruby logger. So a Termite logger is nearly a
51
+ drop-in replacement for the Ruby logger, plus you get Syslog output
52
+ and console output *in addition* to your existing to-file output.
53
+
42
54
  Log Level
43
55
  =========
44
56
 
45
- Termite loggers, like Ruby loggers, allow you to set the logger's level. All events below that
46
- level will be silently discarded, and will also not be sent to non-syslog loggers. You can change
47
- the level with "logger.level = Logger::WARN" and similar.
57
+ Termite loggers, like Ruby loggers, allow you to set the logger's
58
+ level. All events below that level will be silently discarded, and
59
+ will also not be sent to non-syslog loggers. You can change the level
60
+ with "logger.level = Logger::WARN" and similar.
48
61
 
49
- By default, Termite will log events of all severities to standard output, and events of at least
50
- severity :error to standard error. You can set .stdout_level and .stderr_level just like setting
51
- .level above. Level takes precedence over the other two and stderr_level takes precedence over
52
- stdout_level.
62
+ By default, Termite will log events of all severities to standard
63
+ output, and events of at least severity :error to standard error. You
64
+ can set .stdout_level and .stderr_level just like setting .level
65
+ above. Level takes precedence over the other two and stderr_level
66
+ takes precedence over stdout_level.
53
67
 
54
68
  Non-Syslog Logging
55
69
  ==================
56
70
 
57
- If a filename or handle is specified in the constructor, Termite will instantiate a Ruby Logger
58
- with the same parameters and mirror all events to it.
71
+ If a filename or handle is specified in the constructor, Termite will
72
+ instantiate a Ruby Logger with the same parameters and mirror all
73
+ events to it.
59
74
 
60
- You can pass in objects with an :add method to a Termite logger's "add_extra_logger" method, and
61
- from then on all events will be mirrored to that object. This can be useful for chaining loggers
62
- if you need to. Events below the Termite logger's level (see above) won't be mirrored.
75
+ You can pass in objects with an :add method to a Termite logger's
76
+ "add_extra_logger" method, and from then on all events will be
77
+ mirrored to that object. This can be useful for chaining loggers if
78
+ you need to. Events below the Termite logger's level (see above)
79
+ won't be mirrored.
63
80
 
64
81
  Translating to SysLog
65
82
  =====================
66
83
 
67
- When writing to SysLog, Termite translates Ruby Logger severities into SysLog severities. By
68
- default, this is the mapping:
84
+ When writing to SysLog, Termite translates Ruby Logger severities into
85
+ SysLog severities. By default, this is the mapping:
69
86
 
70
87
  Logger => SysLog
71
88
  :unknown => :alert
@@ -78,8 +95,9 @@ Logger => SysLog
78
95
  Configuring with an Ecology
79
96
  ===========================
80
97
 
81
- Termite supports a standard Ecology file. By default, it will look at the location of the current
82
- executable ($0) with extension .ecology. So "bob.rb" would have "bob.ecology" next to it.
98
+ Termite supports a standard Ecology file. By default, it will look at
99
+ the location of the current executable ($0) with extension .ecology.
100
+ So "bob.rb" would have "bob.ecology" next to it.
83
101
 
84
102
  An Ecology is a JSON file of roughly this structure:
85
103
 
@@ -91,41 +109,77 @@ An Ecology is a JSON file of roughly this structure:
91
109
  "app_group": "SuperSpiffyGroup",
92
110
  "precedence": 7
93
111
  },
94
- "console_print": "off",
95
- "filename": "/tmp/bobo.txt",
96
- "shift_age": 10,
97
- "shift_size": 1024000,
98
- "stderr_level": "fatal"
112
+ "sinks": [
113
+ {
114
+ "type": "stdout",
115
+ "color": "green",
116
+ "min_level": "debug",
117
+ "max_level": "warning"
118
+ },
119
+ {
120
+ "type": "stderr",
121
+ "color": "red",
122
+ "min_level": "error"
123
+ },
124
+ {
125
+ "type": "file",
126
+ "filename": "/tmp/bobo.txt",
127
+ "min_level": "warning",
128
+ "shift_age": 10,
129
+ "shift_size": 1024000
130
+ },
131
+ {
132
+ "type": "syslog",
133
+ "transport": "UDP"
134
+ },
135
+ {
136
+ "type": "hastur",
137
+ "udp_port": 9199,
138
+ "labels": {
139
+ "app_flavor": "vanilla",
140
+ "track_for": "jbhat"
141
+ }
142
+ }
143
+ ]
99
144
  }
100
145
  }
101
146
 
102
- Absolutely every part of it is optional, including the presence of the file at all.
147
+ Absolutely every part of it is optional, including the presence of the
148
+ file at all.
103
149
 
104
- You can override the application name, as shown above. Other than the application name,
105
- all Termite-specific parameters are under the "logging" field, as above.
150
+ You can override the application name, as shown above. Other than the
151
+ application name, all Termite-specific parameters are under the
152
+ "logging" field, as above.
106
153
 
107
- The default_component is what application component is given for an add() call by default.
108
- If set, it can be removed with ":component => nil" for a given add() call.
154
+ The default_component is what application component is given for an
155
+ add() call by default. If set, it can be removed with ":component =>
156
+ nil" for a given add() call.
109
157
 
110
158
  Extra JSON fields are added to the JSON data of every add() call.
111
159
 
112
- Console_print can be set to "off" (or "no" or "0") to turn off Termite printing to stderr
113
- and stdout by default at different log levels.
160
+ Console_print can be set to "off" (or "no" or "0") to turn off Termite
161
+ printing to stderr and stdout by default at different log levels.
162
+
163
+ Filename, shift_age and shift_size are the same as Ruby Logger's
164
+ normal initialize parameters. The first is the filename to log to,
165
+ the second is how many total log files to keep, and the third is how
166
+ large each log file can grow. Or the second can be set to a value
167
+ like "daily" or "monthly", and then the third is irrelevant.
114
168
 
115
- Filename, shift_age and shift_size are the same as Ruby Logger's normal initialize
116
- parameters. The first is the filename to log to, the second is how many total log files
117
- to keep, and the third is how large each log file can grow. Or the second can be set to
118
- a value like "daily" or "monthly", and then the third is irrelevant.
169
+ You can also set level, stdout_level and stderr_level explained above.
170
+ We allow numerical (syslog) values, or standard names of Ruby Logger
171
+ severities.
119
172
 
120
- You can also set level, stdout_level and stderr_level explained above. We allow numerical
121
- (syslog) values, or standard names of Ruby Logger severities.
173
+ If you reset your Ecology (usually used for testing), you should
174
+ recreate all your Termite::Logger objects. The old ones will still
175
+ have stale settings from the old Ecology's defaults and data.
122
176
 
123
177
  Releasing within Ooyala
124
178
  =======================
125
179
 
126
180
  Ooyalans, to release Termite to gems.sv2, use the following:
127
181
 
128
- gem build
182
+ rake build
129
183
  rake _0.8.7_ -f ../ooyala_gems.rake gem:push termite-0.0.1.gem
130
184
 
131
185
  Change the version to the actual version you'd like to push.
data/TODO CHANGED
@@ -1,3 +1,9 @@
1
1
  Ecology configuration:
2
- * Extra loggers from Ecology
3
- * Transport protocol from Ecology
2
+ * Load extra loggers from Ecology
3
+ * Load which transport protocol from Ecology
4
+
5
+ When logging:
6
+ * Send call-site with data (configurable depth?)
7
+
8
+ Environment variables:
9
+ * Add variable(s) to set console output when debugging
@@ -1,8 +1,11 @@
1
1
  require "rubygems"
2
+ require "termite/hastur_logger"
3
+ require "termite/syslog_logger"
2
4
  require "termite/version"
3
5
 
4
6
  require "ecology"
5
7
  require "multi_json"
8
+ require "rainbow"
6
9
 
7
10
  require "thread"
8
11
  require "syslog"
@@ -14,7 +17,7 @@ module Termite
14
17
  ##
15
18
  # Maps Logger severities to syslog(3) severities.
16
19
 
17
- LOGGER_MAP = {
20
+ LOGGER_SYSLOG_MAP = {
18
21
  :unknown => :alert,
19
22
  :fatal => :crit,
20
23
  :error => :err,
@@ -23,27 +26,33 @@ module Termite
23
26
  :debug => :debug,
24
27
  }
25
28
 
29
+ # Get Ruby Logger labels for Logger-compatible output
30
+ RUBY_LOGGER_SEV_LABELS = ::Logger::SEV_LABEL
31
+
26
32
  ##
27
- # Maps Ruby Logger log levels to their values so we can silence.
33
+ # Maps Ruby Logger log levels to their numerical values.
28
34
 
29
35
  LOGGER_LEVEL_MAP = {}
30
36
 
31
- LOGGER_MAP.each_key do |key|
37
+ LOGGER_SYSLOG_MAP.each_key do |key|
32
38
  LOGGER_LEVEL_MAP[key] = ::Logger.const_get key.to_s.upcase
33
39
  end
34
40
 
35
41
  ##
36
- # Maps Logger numerical log level values to syslog log levels.
42
+ # Maps Logger numerical log level values to syslog level names.
37
43
 
38
- LEVEL_LOGGER_MAP = {}
44
+ LEVEL_SYSLOG_MAP = {}
39
45
 
40
46
  LOGGER_LEVEL_MAP.invert.each do |level, severity|
41
- LEVEL_LOGGER_MAP[level] = LOGGER_MAP[severity]
47
+ LEVEL_SYSLOG_MAP[level] = LOGGER_SYSLOG_MAP[severity]
42
48
  end
43
49
 
50
+ ##
51
+ # Maps Syslog level names to their numerical severity levels
52
+
44
53
  SYSLOG_SEVERITY_MAP = {}
45
54
 
46
- LOGGER_MAP.values.each do |syslog_severity|
55
+ LOGGER_SYSLOG_MAP.values.each do |syslog_severity|
47
56
  SYSLOG_SEVERITY_MAP[syslog_severity] = ::Syslog.const_get("LOG_" + syslog_severity.to_s.upcase)
48
57
  end
49
58
 
@@ -63,7 +72,7 @@ module Termite
63
72
  EOM
64
73
  end
65
74
 
66
- LOGGER_MAP.each_key do |level|
75
+ LOGGER_SYSLOG_MAP.each_key do |level|
67
76
  make_methods level
68
77
  end
69
78
 
@@ -73,32 +82,156 @@ module Termite
73
82
  attr_accessor :level
74
83
  attr_reader :stdout_level
75
84
  attr_reader :stderr_level
76
- attr_reader :file_logger
77
85
 
78
- def initialize(logdev = nil, shift_age = 0, shift_size = 1048576, options = {})
79
- options = logdev if(logdev.is_a?(Hash))
86
+ def initialize(logdev = nil, shift_age = nil, shift_size = nil, options = {})
87
+ if logdev.is_a?(Hash)
88
+ options = logdev
89
+ logdev = nil
90
+ end
91
+
92
+ @loggers ||= []
93
+ @log_filename ||= logdev
94
+ @shift_age ||= shift_age
95
+ @shift_size ||= shift_size
80
96
 
81
97
  Ecology.read
98
+ read_ecology_data(options)
99
+ end
82
100
 
83
- read_ecology_data
84
- @log_filename ||= logdev
101
+ private
85
102
 
86
- @file_logger = ::Logger.new(@log_filename, @shift_age || shift_age, @shift_size || shift_size) if @log_filename
87
- @extra_loggers << @file_logger if @file_logger
103
+ def read_ecology_data(options = {})
104
+ @application = Ecology.application
105
+ @default_component = options[:component] || Ecology.property("logging::default_component") ||
106
+ options[:default_component]
107
+ # @console_print defaults to "yes", but can be nil if "no", "off" or "0" is specified
108
+ @console_print = Ecology.property("logging::console_print") || options[:console_print] || "yes"
109
+ @console_print = nil if ["no", "off", "0"].include?(@console_print)
110
+ @default_fields = Ecology.property("logging::extra_json_fields") || options[:extra_json_fields] || {}
111
+ @use_logger_prefix = Ecology.property("logging::use_logger_prefix") || options[:use_logger_prefix]
112
+ @level = Ecology.property("logging::level") || options[:level]
113
+ @level = string_to_severity(@level) if @level
114
+ @level = ::Logger::DEBUG if @level.nil? || ENV["TERMITE_DEBUG"]
88
115
 
89
- # For UDP socket
90
- @server_addr = options[:address] || "0.0.0.0"
91
- @server_port = options[:port] ? options[:port].to_i : 514
116
+ sinks = Ecology.property("logging::sinks")
117
+ sinks ? instantiate_sinks(sinks, options) : read_unsinked_ecology(options)
118
+ end
92
119
 
93
- @@sockets ||= {}
94
- key = "#{@server_addr}:#{@server_port}"
95
- @@sockets[key] ||= UDPSocket.new
96
- @socket = @@sockets[key]
120
+ # This is the codepath for ecology files that do not have a 'sinks' section defined
121
+ def read_unsinked_ecology(options)
122
+ sinks = []
123
+ # File Sink
124
+ file_sink = {"type" => "file", "min_level" => @level}
125
+ file_sink["filename"] = Ecology.property("logging::filename", :as => :path) ||
126
+ options[:logging_filename]
127
+ file_sink["shift_age"] = Ecology.property("logging::shift_age") || options[:shift_age]
128
+ file_sink["shift_size"] = Ecology.property("logging::shift_size") || options[:shift_size]
129
+ file_sink["logger_prefix?"] = @use_logger_prefix if @use_logger_prefix
130
+ sinks << file_sink if file_sink["filename"]
131
+
132
+ # STDERR Sink
133
+ stderr_sink = {"type" => "file", "filename" => STDERR}
134
+ @stderr_level = Ecology.property("logging::stderr_level") || options[:stderr_level] || ::Logger::ERROR
135
+ stderr_sink["min_level"] = string_to_severity(@stderr_level) if @stderr_level
136
+ if @use_logger_prefix
137
+ stderr_sink["logger_prefix?"] = @use_logger_prefix
138
+ else
139
+ stderr_prefix = Ecology.property("logging::stderr_logger_prefix") || options[:stderr_logger_prefix]
140
+ stderr_sink["logger_prefix?"] = stderr_prefix if stderr_prefix
141
+ end
142
+ stderr_sink["color"] = Ecology.property("logging::stderr_color") || options[:stderr_color]
143
+ stderr_sink["color"] ||= "red" if STDERR.tty?
144
+ sinks << stderr_sink if @console_print
145
+
146
+ # STDOUT Sink
147
+ stdout_sink = {"type" => "file", "filename" => STDOUT}
148
+ @stdout_level = Ecology.property("logging::stdout_level") || options[:stdout_level] || ::Logger::INFO
149
+ stdout_sink["min_level"] = string_to_severity(@stdout_level) if @stdout_level
150
+ stdout_sink["max_level"] = string_to_severity(@stderr_level) - 1
151
+ if @use_logger_prefix
152
+ stdout_sink["logger_prefix?"] = @use_logger_prefix
153
+ else
154
+ stdout_prefix = Ecology.property("logging::stdout_logger_prefix") || options[:stdout_logger_prefix]
155
+ stdout_sink["logger_prefix?"] = stdout_prefix if stdout_prefix
156
+ end
157
+ stdout_sink["color"] = Ecology.property("logging:stdout_color") || options[:stdout_color]
158
+ stdout_sink["color"] ||= "blue" if STDOUT.tty?
159
+ sinks << stdout_sink if @console_print
160
+
161
+ # Syslog Sink
162
+ syslog_sink = {"type" => "syslog"}
163
+ syslog_sink["transport"] = Ecology.property("logging::transport") || options[:transport]
164
+ sinks << syslog_sink
165
+
166
+
167
+ # Set up sinks
168
+ instantiate_sinks(sinks, options)
97
169
  end
98
170
 
99
- private
171
+ # For each sink, and to loggers
172
+ def instantiate_sinks(sinks, options)
173
+ sinks = sinks.dup
174
+ syslog = false
175
+ # Maximum Level
176
+ min_level = 5
177
+ sinks.each do |sink|
178
+ # Set min level if lower than current (@level if not defined)
179
+ if sink["min_level"]
180
+ sink_level = string_to_severity(sink["min_level"])
181
+ min_level = sink_level if sink_level < min_level
182
+ else min_level = @level
183
+ end
184
+ cur_logger = case sink["type"]
185
+ when "file"
186
+ sink["newline?"] = true unless sink.has_key? "newline?"
187
+ case sink["filename"]
188
+ when STDOUT
189
+ ::Logger.new(STDOUT) if @console_print
190
+ when STDERR
191
+ ::Logger.new(STDERR) if @console_print
192
+ else
193
+ ::Logger.new(sink["filename"], sink["shift_age"] || 0, sink["shift_size"] || 1048576)
194
+ end
195
+ when "stdout"
196
+ sink["newline?"] = true unless sink.has_key? "newline?"
197
+ ::Logger.new(STDOUT) if @console_print
198
+ when "stderr"
199
+ sink["newline?"] = true unless sink.has_key? "newline?"
200
+ ::Logger.new(STDERR) if @console_print
201
+ when "syslog"
202
+ syslog = true
203
+ setup_syslog_logger(sink, options)
204
+ when "hastur"
205
+ setup_hastur_logger(sink, options)
206
+ end
207
+ sink["logger"] = cur_logger
208
+ end
209
+ @loggers = sinks
210
+
211
+ # Create syslog logger if not defined in sinks
212
+ unless syslog
213
+ min_level = @level
214
+ add_logger(setup_syslog_logger(options), "type" => "syslog", "min_level" => min_level)
215
+ end
216
+
217
+ # Constructor params logger
218
+ if @log_filename
219
+ min_level = @level
220
+ add_logger(::Logger.new(@log_filename, @shift_age || 0, @shift_size || 1048576), "type" => "file",
221
+ "filename" => @log_filename,
222
+ "shift_age" => @shift_age || 0,
223
+ "shift_size" => @shift_size || 1048576,
224
+ "logger_prefix?" => @use_logger_prefix,
225
+ "min_level" => @level,
226
+ "newline?" => true
227
+ )
228
+ end
229
+ # If the min level of all loggers is greater than @level, use that
230
+ @level = [@level, min_level].max
231
+ end
100
232
 
101
233
  def string_to_severity(str)
234
+ return str if str.is_a? Numeric
102
235
  orig_string = str
103
236
  str = str.strip.downcase
104
237
  return str.to_i if str =~ /\d+/
@@ -107,61 +240,60 @@ module Termite
107
240
  ret
108
241
  end
109
242
 
110
- def read_ecology_data
111
- @application = Ecology.application
112
-
113
- @extra_loggers = []
114
-
115
- # @console_print defaults to "yes", but can be nil if "no", "off" or "0" is specified
116
- @console_print = Ecology.property("logging::console_print") || "yes"
117
- @console_print = nil if ["no", "off", "0"].include?(@console_print)
118
-
119
- @log_filename = Ecology.property("logging::filename", :as => :path)
120
- @shift_age = Ecology.property("logging::shift_age")
121
- @shift_size = Ecology.property("logging::shift_size")
122
- @default_component = Ecology.property("logging::default_component")
123
- @level = Ecology.property("logging::level")
124
- @level = string_to_severity(@level) if @level
125
- @stderr_level = Ecology.property("logging::stderr_level")
126
- @stderr_level = string_to_severity(@stderr_level) if @stderr_level
127
- @stdout_level = Ecology.property("logging::stdout_level")
128
- @stdout_level = string_to_severity(@stdout_level) if @stdout_level
243
+ def setup_syslog_logger(sink, options)
244
+ # For UDP socket
245
+ @server_addr = options[:address] || "0.0.0.0"
246
+ @server_port = options[:port] ? options[:port].to_i : 514
247
+ @socket = find_or_create_socket(@server_addr, @server_port)
248
+ SyslogLogger.new(@socket, @server_addr, @server_port, sink["transport"])
249
+ end
129
250
 
130
- @default_fields = Ecology.property("logging::extra_json_fields") || {}
251
+ def setup_hastur_logger(sink, options)
252
+ @hastur_addr = options[:hastur_address] || "127.0.0.1"
253
+ @hastur_port = sink["udp_port"] || options[:hastur_port] || 8125
254
+ @hastur_socket = find_or_create_socket(@hastur_addr, @hastur_port)
255
+ HasturLogger.new(@hastur_socket, @hastur_addr, @hastur_port, sink["labels"])
256
+ end
131
257
 
132
- @level ||= ::Logger::DEBUG
133
- @stdout_level ||= ::Logger::INFO
134
- @stderr_level ||= ::Logger::ERROR
258
+ def find_or_create_socket(addr, port)
259
+ @@sockets ||= {}
260
+ key = "#{addr}:#{port}"
261
+ @@sockets[key] ||= UDPSocket.new
135
262
  end
136
263
 
137
264
  public
138
265
 
139
- def add_logger(logger)
140
- @extra_loggers << logger
266
+ def add_logger(logger, options={})
267
+ if logger.is_a? Hash
268
+ @loggers << logger
269
+ else
270
+ options["logger"] = logger
271
+ @loggers << options
272
+ end
141
273
  end
142
274
 
143
275
  def socket
144
276
  @socket
145
277
  end
146
278
 
147
- def raw_add(severity, message = nil, data = nil, options = {}, &block)
148
- raw_message = message
279
+ COLORS = [:black, :red, :green, :yellow, :blue, :magenta, :cyan, :white, :default]
280
+
281
+ def raw_add(severity, raw_message = nil, data = nil, options = {}, &block)
149
282
  # Severity is a numerical severity using Ruby Logger's scale
150
283
  severity ||= ::Logger::UNKNOWN
151
284
  return true if severity < @level
152
285
 
153
- application = options[:application] || @application
154
-
155
- component ||= @default_component
286
+ application = options[:application] || @application
287
+ component = @default_component
156
288
  component = options[:component] if options.has_key?(:component)
157
- if component
158
- application += ":" + component
159
- end
289
+
290
+ combined_app = application + ":" + component if component
291
+ app_data = {:combined => combined_app, :app => application, :component => component}
160
292
 
161
293
  data ||= {}
162
294
  if data.is_a?(Hash)
163
295
  data = @default_fields.merge(data)
164
- data = MultiJson.encode(data)
296
+ data = MultiJson.dump(data)
165
297
  elsif data.is_a?(String)
166
298
  # Can't merge a JSON string with default data
167
299
  raise "Can't merge a JSON string with extra fields!" unless @default_fields.empty?
@@ -169,42 +301,37 @@ module Termite
169
301
  raise "Unknown data object passed as JSON!"
170
302
  end
171
303
 
172
- tid = Ecology.thread_id(Thread.current)
173
304
  time = Time.now
174
- day = time.strftime("%b %d").sub(/0(\d)/, ' \\1')
175
- time_of_day = time.strftime("%T")
176
- hostname = Socket.gethostname
177
- tag = Syslog::LOG_LOCAL6 + SYSLOG_SEVERITY_MAP[LEVEL_LOGGER_MAP[severity]]
178
-
179
- syslog_string = "<#{tag}>#{day} #{time_of_day} #{hostname} #{application} [#{Process.pid}]: [#{tid}] "
180
- full_message = clean(message || block.call)
181
-
182
- # ruby_severity is the Ruby Logger severity as a symbol
183
- ruby_severity = LOGGER_LEVEL_MAP.invert[severity]
184
-
185
- full_message.split("\n").each do |line|
186
- message = syslog_string + "#{line} #{data}"
187
-
188
- begin
189
- @socket.send(message, 0, @server_addr, @server_port)
190
- rescue Exception
191
- # Didn't work. Try built-in Ruby syslog
192
- require "syslog"
193
- Syslog.open(application, Syslog::LOG_PID | Syslog::LOG_CONS) do |s|
194
- s.error("UDP syslog failed! Falling back to libc syslog!") rescue nil
195
- s.send(LEVEL_LOGGER_MAP[severity], "#{line} #{data}") rescue nil
196
- end
197
- end
198
- end
199
-
200
- if @console_print && severity >= @stderr_level
201
- STDERR.puts raw_message
202
- elsif @console_print && severity >= @stdout_level
203
- STDOUT.puts raw_message
305
+ full_message = if raw_message
306
+ raw_message
307
+ elsif block
308
+ block.call
309
+ else
310
+ "Error! Logger called with no message or block to execute! Trace: #{caller.join(", ")}"
204
311
  end
205
-
206
- @extra_loggers.each do |logger|
207
- logger.send(ruby_severity, raw_message) rescue nil
312
+ full_message = clean(full_message)
313
+ # Lifted from Logger::Formatter
314
+ ruby_logger_severity = RUBY_LOGGER_SEV_LABELS[severity]
315
+ ruby_logger_message = "%s, [%s#%d] %5s -- %s: %s" % [ruby_logger_severity[0..0],
316
+ (time.strftime("%Y-%m-%dT%H:%M:%S.") << "%06d " % time.usec),
317
+ $$, ruby_logger_severity, "", full_message]
318
+
319
+ @loggers.each do |sink|
320
+ next if (sink["min_level"] && severity < string_to_severity(sink["min_level"])) ||
321
+ (sink["max_level"] && severity > string_to_severity(sink["max_level"])) ||
322
+ sink["logger"].nil?
323
+ message = sink["logger_prefix?"] ? ruby_logger_message : full_message
324
+ message += " #{data}" if sink["logger_data?"]
325
+ if sink["logger"].respond_to?(:send_message)
326
+ sink["logger"].send_message(severity, message, app_data, time, data)
327
+ else
328
+ message += "\n" if sink["newline?"] && sink["newline?"] != "false"
329
+ if sink["color"]
330
+ color = (COLORS.include? sink["color"].to_sym) ? sink["color"].to_sym : sink["color"]
331
+ message = message.color(color)
332
+ end
333
+ sink["logger"] << message
334
+ end rescue nil
208
335
  end
209
336
 
210
337
  true
@@ -256,4 +383,52 @@ module Termite
256
383
  return message
257
384
  end
258
385
  end
386
+
387
+ def FakeLogger
388
+ Termite::LOGGER_SYSLOG_MAP.each_key do |key|
389
+ define_method(LOGGER_LEVEL_MAP[key]) do
390
+ # Do nothing
391
+ end
392
+ end
393
+
394
+ # Alias the other methods to a do-nothing method
395
+ alias :add :error
396
+ alias :<< :error
397
+ alias :log :error
398
+ alias :silence :error
399
+ alias :add_logger :error
400
+
401
+ # Read and write level
402
+ attr_accessor :level
403
+
404
+ # For now, don't read an Ecology, just mock out these accessors.
405
+
406
+ def stdout_level
407
+ 4
408
+ end
409
+
410
+ def stderr_level
411
+ 2
412
+ end
413
+ end
414
+ end
415
+
416
+ module Termite
417
+ module Thread
418
+ def self.new(*args, &block)
419
+ ::Thread.new do
420
+ begin
421
+ block.call
422
+ rescue ::Exception
423
+ if args[0].respond_to?(:warn)
424
+ logger = args[0]
425
+ else
426
+ logger = ::Termite::Logger.new(*args)
427
+ end
428
+ logger.warn "Exception in thread: #{$!.message}"
429
+ logger.warn " Backtrace:\n#{$!.backtrace.join("\n")}"
430
+ end
431
+ end
432
+ end
433
+ end
259
434
  end