multilog 0.1.0a

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 (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: []