multilog 0.1.0a

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/multilog.rb +191 -0
  3. metadata +45 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2d1171ef2208798e22e0a57c80de69d807ad8aec
4
+ data.tar.gz: e37fdfb4646fe2fa18d1387fa500f082f1254d00
5
+ SHA512:
6
+ metadata.gz: 9861531007285c0c8ca09b88a92e0957d3ed1c9f95b06bd1db4b148cb8d07906e4681e1f234d6ff626dda3900f73a3c72e1458a145a106e30e16be16d0afd9eb
7
+ data.tar.gz: 047a66e172175dfb8e2be1324269efe50f4325c395671a944780cbb2e709032c8d3a5718aae6eca7e64a49dd2706f53cddd8640ed4b637c12d513377c17cd254
data/lib/multilog.rb ADDED
@@ -0,0 +1,191 @@
1
+ require 'logger'
2
+
3
+ # Logs to many devices, each of which may have an individual
4
+ # level and device.
5
+ #
6
+ # Acts in compliance with other configuration options from ruby's
7
+ # default Logger class.
8
+ #
9
+ # Author:: Stephen Wattam <http://stephenwattam.com>
10
+ # License:: Beerware
11
+ #
12
+ class MultiLog < Logger
13
+
14
+ # Version, for convenience.
15
+ VERSION = '0.1.0a'
16
+
17
+ # Default log level set to Logger::UNKNOWN
18
+ DEFAULT_LEVEL = Logger::UNKNOWN
19
+
20
+ # Create a simple log object with one log level and one device
21
+ #
22
+ # May be called in the same manner as ruby's Logger class,
23
+ # or with a list of logs specified in the same format as #configure_logs
24
+ #
25
+ def initialize(logdevs = {}, progname=nil, shift_age = 0, shift_size = 1048576)
26
+ super(nil, shift_age, shift_size)
27
+ @progname = progname
28
+ @shift_age = shift_age
29
+ @shift_size = shift_size
30
+ @lowest_level = DEFAULT_LEVEL
31
+ configure_logs(logdevs)
32
+ end
33
+
34
+ # Set all logging devices as per the hash provided.
35
+ # Will remove all current logs in the process.
36
+ #
37
+ # name :: Default: :default :: The name of the log, used when identifying it or removing it later
38
+ # dev :: Default: STDOUT :: The device to be used. Should be an IO and will be closed on calling #close
39
+ # level :: Default: The value of MultiLog.DEFAULT_LEVEL :: A log level as per ruby's Logger class or a string representing it.
40
+ # shift_age :: Default: The value of @shift_age :: As per ruby's Logger
41
+ # shift_size :: Default: The value of @shift_size :: As per ruby's Logger
42
+ #
43
+ def configure_logs(logdevs = {})
44
+ # Remove all exsiting logs
45
+ @logdevs.each{ |name, ld| remove_log(name) } if @logdevs
46
+
47
+ # Parse logdevs hash options
48
+ @logdevs = {}
49
+ logdevs = [logdevs] if logdevs.is_a? Hash
50
+
51
+ # If the user provides a device then set up a single log as :log
52
+ unless logdevs.is_a? Array then
53
+ @logdevs[:default] = {:dev => logdevs, :level => DEFAULT_LEVEL}
54
+ @lowest_level = @logdevs[:default][:level]
55
+ return
56
+ end
57
+
58
+ # If the user provides a hash, check each arg
59
+ logdevs.each do |ld|
60
+ name = ld[:name] ||= :default
61
+ dev = ld[:dev] ||= $stdout
62
+ level = ld[:level] ||= DEFAULT_LEVEL
63
+ shift_age = ld[:shift_age] ||= @shift_age
64
+ shift_size = ld[:shift_size] ||= @shift_size
65
+ level = MultiLog.string_to_level(level) unless level.is_a? Fixnum
66
+
67
+ # Add to the name deely.
68
+ add_log(name, dev, level, shift_age, shift_size)
69
+ end
70
+ end
71
+
72
+ # Add a log to the list of existing logs, without removing others
73
+ #
74
+ # name :: The name of the log
75
+ # destination:: A device to log to
76
+ # level :: As per ruby's Logger class
77
+ # shift_age :: As per ruby's Logger class
78
+ # shift_size :: As per ruby's Logger class
79
+ #
80
+ def add_log(name, destination, level, shift_age = 0, shift_size = 1048576)
81
+ dev = LogDevice.new(destination, :shift_age => shift_age, :shift_size => shift_size)
82
+
83
+ @logdevs[name] = {:dev => dev, :level => level}
84
+ @lowest_level = level if (not @lowest_level) or level < @lowest_level
85
+ end
86
+
87
+ # Stop logging to one of the logs
88
+ def remove_log(name)
89
+ if(@logdevs[name])
90
+ # Back up old level
91
+ old_level = @logdevs[name][:level]
92
+
93
+ # Remove
94
+ @logdevs.delete(name)
95
+
96
+ # Update lowest level if we need to
97
+ @lowest_level = @logdevs.values.map{|x| x[:level] }.min if old_level == @lowest_level
98
+ end
99
+ end
100
+
101
+ # Print a summary of log output devices to the log, at such a level
102
+ # that all logs see it.
103
+ def summarise
104
+ add(@lowest_level, "Summary of logs:")
105
+ if(@logdevs.length > 0)
106
+ c = 0
107
+ @logdevs.each{|name, ld|
108
+ msg = " (#{c+=1}/#{@logdevs.length}) #{name} (level: #{MultiLog.level_to_string(ld[:level])}, device: fd=#{ld[:dev].dev.fileno}#{ld[:dev].dev.tty? ? " TTY" : ""}#{ld[:dev].filename ? " filename=#{ld[:dev].filename}" : ""})"
109
+ add(@lowest_level, msg)
110
+ }
111
+ else
112
+ add(@lowest_level, " *** No logs!") # Amusingly, this can never output
113
+ end
114
+ end
115
+
116
+ # Set the log level of one of the logs to a given Logger level.
117
+ def set_level(name, level=nil)
118
+ # Default
119
+ unless level then
120
+ level = name
121
+ name = nil
122
+ end
123
+
124
+ # Look up the level if the user provided a :symbol or "string"
125
+ level = MultiLog.string_to_level(level.to_s) unless level.is_a? Fixnum
126
+
127
+ if name
128
+ # Set a specific one
129
+ raise "No log by the name '#{name}'" unless @logdevs[name]
130
+ @logdevs[name][:level] = level
131
+ else
132
+ # Set them all by default
133
+ @logdevs.each{|name, logdev| logdev[:level] = level }
134
+ end
135
+ end
136
+
137
+ # Returns the log level of a log
138
+ def get_level(name = nil)
139
+ name = :default unless name
140
+ return nil unless @logdevs[name]
141
+ return @logdevs[name][:level]
142
+ end
143
+
144
+ # Overrides the basic internal add in Logger
145
+ def add(severity, message = nil, progname = nil, &block)
146
+ severity ||= UNKNOWN
147
+
148
+ # give up if no logdevs or if too low a severity
149
+ return true if severity < @lowest_level or (not @logdevs.values.map{ |ld| ld[:dev].nil? }.include?(false))
150
+
151
+ # Set progname to nil unless it is explicitly specified
152
+ progname ||= @progname
153
+ if message.nil?
154
+ if block_given?
155
+ message = yield
156
+ else
157
+ message = progname
158
+ progname = @progname
159
+ end
160
+ end
161
+
162
+ # Sync time across the logs and output only if above the log level for that device
163
+ msg = format_message(format_severity(severity), Time.now, progname, message)
164
+ @logdevs.each do |name, ld|
165
+ ld[:dev].write(msg) unless ld[:dev].nil? && ld[:level] <= severity
166
+ end
167
+ return true
168
+ end
169
+
170
+ # Convert a log level to a string.
171
+ #
172
+ # Used in the output summary
173
+ def self.level_to_string(lvl)
174
+ labels = %w(DEBUG INFO WARN ERROR FATAL)
175
+ return labels[lvl] || "UNKNOWN"
176
+ end
177
+
178
+ # Convert a string to a logger level number.
179
+ def self.string_to_level(str)
180
+ labels = %w(DEBUG INFO WARN ERROR FATAL)
181
+ return labels.index(str.to_s.upcase) || Logger::UNKNOWN
182
+ end
183
+
184
+ # Close the log and all associated devices.
185
+ def close
186
+ @logdevs.each do |name, ld|
187
+ ld[:dev].close
188
+ end
189
+ end
190
+ end
191
+
metadata ADDED
@@ -0,0 +1,45 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: multilog
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0a
5
+ platform: ruby
6
+ authors:
7
+ - Stephen Wattam
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-19 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A drop-in replacement for ruby's Logger supporting multiple outputs at
14
+ various levels
15
+ email: stephenwattam@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/multilog.rb
21
+ homepage: http://stephenwattam.com/git/cgit.cgi/multilog/
22
+ licenses:
23
+ - Beerware
24
+ metadata: {}
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - '>'
37
+ - !ruby/object:Gem::Version
38
+ version: 1.3.1
39
+ requirements: []
40
+ rubyforge_project:
41
+ rubygems_version: 2.0.14
42
+ signing_key:
43
+ specification_version: 4
44
+ summary: A multiple-output extension of ruby's Logger
45
+ test_files: []