termite 0.0.10 → 0.0.20

Sign up to get free protection for your applications and to get access to all the features.
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