colortail 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,3 +2,4 @@ pkg
2
2
  doc
3
3
  Manifest
4
4
  .swp
5
+ tmp/*
@@ -1,3 +1,10 @@
1
+ ### colortail 0.1.7 2010-05-10
2
+
3
+ * FEATURE: Color groupings can now be applied on a per file basis (#10)
4
+ * FEATURE: Can now pipe input into colortail (#7)
5
+ * FEATURE: Filename prefixes are now available (-F) (#9)
6
+ * BUGFIX: Removed "No such group" on match listing (#5)
7
+
1
8
  ### colortail 0.1.6 2010-04-26
2
9
 
3
10
  * BUGFIX: Lots of bugfixes as a result of finally adding testing
@@ -65,9 +65,23 @@ Using ColorTail is similar to using tail. The main assumption is that you will a
65
65
 
66
66
  #### Tailing with groups
67
67
 
68
- The command below will tail the **/var/log/messages** file using the syslog group. The example config [examples/colortail.rb](http://www.codaset.com/elubow/colortail/source/master/blob/examples/colortail.rb) shows a _syslog_ grouping that is used in command below:
68
+ The command below will tail the **/var/log/messages** file using the syslog group. The example config [examples/colortail.rb](http://www.codaset.com/elubow/colortail/source/master/blob/examples/colortail.rb) shows a _syslog_ grouping that is used in command below (the below 2 commands are equivilent):
69
69
 
70
- # colortail -g syslog /var/log/messages
70
+ # colortail -g syslog /var/log/messages
71
+ # cat /var/log/messages | colortail -g syslog
72
+
73
+ #### Tailing multiple files
74
+
75
+ To tail multiple files can be confusing, especially when you don't know which file you are seeing. Use the **-F** option to show the filenames at the beginning of each colored line.
76
+
77
+ # colortail -F -g syslog /var/log/messages /var/log/secure.log
78
+
79
+ #### Tailing multiple files using different color groups
80
+
81
+ You can also tail multiple files using different color groups. Currently, the separater is *#*. If no grouping is specified with the file or the grouping specified doesn't exist, colortail will default to the one specied on the command line.
82
+
83
+ # colortail /var/log/messages#syslog /var/log/secure.log#otherlog
84
+ # colortail -g syslog /var/log/messags#nosuchgroup /var/log/secure.log#secure
71
85
 
72
86
  ## Caveats and Intended Behaviors ##
73
87
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.6
1
+ 0.1.7
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{colortail}
8
- s.version = "0.1.6"
8
+ s.version = "0.1.7"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Eric Lubow"]
12
- s.date = %q{2010-04-26}
12
+ s.date = %q{2010-05-09}
13
13
  s.default_executable = %q{colortail}
14
14
  s.description = %q{Tail a file and color lines based on regular expressions within that line. By setting up multiple expression and color groups in the configuration file, you can apply highlighting to a file while its being tailed.}
15
15
  s.email = %q{eric@lubow.org}
@@ -2,9 +2,16 @@ module ColorTail
2
2
 
3
3
  class Application
4
4
  class << self
5
+ def version
6
+ version = File.read("#{File.join(File.dirname(__FILE__), '..')}/../VERSION").chomp!
7
+ "#{File.basename($0)} v#{version}"
8
+ end
9
+
5
10
  def run!(*arguments)
11
+ require 'fcntl'
12
+
6
13
  opt = ColorTail::Options.new(arguments)
7
- files = opt[:files]
14
+ filelist = opt[:files]
8
15
  options = opt[:options]
9
16
 
10
17
  # Deal with any/all options issues
@@ -15,9 +22,16 @@ module ColorTail
15
22
 
16
23
  # Show the help menu if desired
17
24
  if options[:help]
25
+ $stderr.puts version()
18
26
  $stderr.puts opt.opts
19
27
  return 1
20
28
  end
29
+
30
+ # Show the version
31
+ if options[:version]
32
+ $stderr.puts version()
33
+ return 1
34
+ end
21
35
 
22
36
 
23
37
  # The meat of the program
@@ -25,11 +39,11 @@ module ColorTail
25
39
  # Read the config file if it exists
26
40
  if File.exists?(options[:conf])
27
41
  config = ColorTail::Configuration.new(options[:conf])
28
- @match_group = config.load_opts(options[:group])
42
+ match_group = config.load_opts(options[:group])
29
43
  else
30
44
  # Create this to ensure we always have a value for this array
31
- @match_group = Array.new
32
- @match_group.push( 'default' => [] )
45
+ match_group = Array.new
46
+ match_group.push( 'default' => [] )
33
47
  end
34
48
 
35
49
  # Display the list of available groups and exit
@@ -42,48 +56,116 @@ module ColorTail
42
56
  end
43
57
  return 1
44
58
  end
45
-
46
- # Before we go any further, check for existance of files
47
- @files_exist = false
48
- files.each do |file|
49
- if File.exists?(file)
50
- @files_exist = true
51
- break
52
- end
53
- end
54
-
55
- # If we have no files, tell them and show the help
56
- unless @files_exist
57
- $stderr.puts "Please check to make sure the files exist ..."
58
- $stderr.puts opt.opts
59
- return 1
60
- end
61
-
59
+
60
+ # Create the default logging object
62
61
  logger = ColorTail::Colorize.new()
63
62
 
64
63
  # Add the color match array if we aren't using the default
65
- if @match_group.class == Array
66
- @match_group.each do |matcher|
64
+ if match_group.class == Array
65
+ match_group.each do |matcher|
67
66
  logger.add_color_matcher( matcher )
68
67
  end
69
68
  else
70
- logger.add_color_matcher( @match_group )
69
+ logger.add_color_matcher( match_group )
71
70
  end
72
-
73
- # Create a thread for each file
74
- threads = []
75
- files.each do |file|
76
- threads[files.index(file)] = Thread.new {
77
- tailer = ColorTail::TailFile.new( file )
78
-
79
- # First display the last 10 lines of each file in ARGV
80
- tailer.interval = 10
81
- tailer.backward( 10 )
82
-
83
- # Tail the file and show new lines
84
- tailer.tail { |line| logger.log( file, line ) }
85
- }
86
- threads[files.index(file)].run
71
+
72
+ # Create an empty array of threads
73
+ threads = Array.new
74
+
75
+ # Set $stdin to be non-blocking
76
+ $stdin.fcntl(Fcntl::F_SETFL,Fcntl::O_NONBLOCK)
77
+
78
+ begin
79
+ threads[0] = Thread.new {
80
+ begin
81
+ $stdin.each_line do |line|
82
+ if options[:filename_prefix]
83
+ logger.log( nil, line, "STDIN: " )
84
+ else
85
+ logger.log( nil, line )
86
+ end
87
+ end
88
+ rescue Errno::EAGAIN
89
+ # Remove this thread since we won't be reading from $stdin
90
+ threads.delete(0)
91
+ end
92
+ }.run
93
+
94
+ # Check to see if there are files in the files array
95
+ if filelist.size > 0
96
+ # Before we go any further, check for existance of files
97
+ @files_exist = false
98
+ files = Hash.new
99
+ filelist.each do |file|
100
+ filename = String.new
101
+ group = String.new
102
+ filename,group = file.split('#')
103
+ if group.nil?
104
+ files[filename] = options[:group]
105
+ else
106
+ files[filename] = group
107
+ end
108
+
109
+ # Check for individual files and ignore file if doesn't exist
110
+ if File.exists?(filename)
111
+ @files_exist = true
112
+ else
113
+ $stderr.puts("#{filename} does not exist, skipping...")
114
+ filelist.delete(file)
115
+ end
116
+ end
117
+
118
+ # If we have no files, tell them and show the help
119
+ if !@files_exist and (threads.class == Array.class and threads.size <= 2)
120
+ $stderr.puts "Please check to make sure the files exist ..."
121
+ $stderr.puts opt.opts
122
+ return 1
123
+ end
124
+
125
+ # Create a thread for each file
126
+ files.each_pair do |filename, grouping|
127
+ threads.push Thread.new {
128
+ # Figure out if grouping exists, if not fall back to global default
129
+ if config.group_exists?(grouping)
130
+ # Create a new per file logger object per file
131
+ file_logger = ColorTail::Colorize.new()
132
+
133
+ # Redefine match_group since we have a new grouping
134
+ match_group = config.load_opts(grouping)
135
+
136
+ # Add the color match array if we aren't using the default
137
+ if match_group.class == Array
138
+ match_group.each do |matcher|
139
+ file_logger.add_color_matcher( matcher )
140
+ end
141
+ else
142
+ file_logger.add_color_matcher( match_group )
143
+ end
144
+
145
+ # There is no such group, so we fall back to the default here
146
+ else
147
+ file_logger = logger
148
+ end
149
+
150
+ # Create the new tailer object
151
+ tailer = ColorTail::TailFile.new( filename )
152
+
153
+ # First display the last 10 lines of each file in ARGV
154
+ tailer.interval = 10
155
+ tailer.backward( 10 )
156
+
157
+ # Tail the file and show new lines
158
+ tailer.tail do |line|
159
+ if options[:filename_prefix]
160
+ file_logger.log( filename, line, "#{filename}: ")
161
+ else
162
+ file_logger.log( filename, line )
163
+ end
164
+ end
165
+ }.run
166
+ end
167
+ end
168
+
87
169
  end
88
170
 
89
171
  # Let the threads do their real work
@@ -93,15 +175,22 @@ module ColorTail
93
175
 
94
176
  # If we get a CTRL-C, catch it (rescue) and send it for cleanup
95
177
  rescue Interrupt
96
- thread_cleanup(threads)
178
+ thread_cleanup(threads) if defined? threads
179
+ rescue NoInputError
180
+ $stderr.puts "Please enter a file to tail..."
181
+ $stderr.puts opt.opts
182
+ return 1
97
183
  end
98
184
 
185
+ # We should never make it here, but just in case...
99
186
  return 0
100
187
  end
101
188
 
102
189
  def thread_cleanup(threads)
103
- threads.each do |thread|
104
- thread.kill
190
+ if threads.class == Array.class and threads.size > 0
191
+ threads.each do |thread|
192
+ thread.kill
193
+ end
105
194
  end
106
195
  $stderr.puts "Terminating..."
107
196
  exit
@@ -113,6 +202,9 @@ module ColorTail
113
202
  end
114
203
 
115
204
 
205
+ class NoInputError < StandardError
206
+ end
207
+
116
208
  class FileDoesNotExist < StandardError
117
209
  end
118
210
 
@@ -4,16 +4,17 @@ module ColorTail
4
4
  def initialize(conf)
5
5
  @config_file = conf
6
6
  if File.exists?(conf)
7
- @config = File.read(conf)
7
+ load @config_file
8
8
  else
9
9
  raise FileDoesNotExist, "Config file #{@config_file} cannot be found."
10
10
  end
11
11
  end
12
12
 
13
- def colorit(group, groupings)
14
- if groupings.class == Hash
15
- if groupings.has_key?( group )
16
- return groupings[group]
13
+ def colorit(group)
14
+ if Groupings.class == Hash
15
+ Groupings["default"] = [] unless Groupings.has_key?('default')
16
+ if Groupings.has_key?( group )
17
+ return Groupings[group]
17
18
  else
18
19
  $stderr.puts "No such group '#{group}', falling back to default."
19
20
  return "'default' => []"
@@ -27,11 +28,8 @@ module ColorTail
27
28
  # isn't available in the configuration object until after a new object
28
29
  # has been instantiated.
29
30
  def load_opts(group)
30
- colorset = []
31
- if File.exists?(@config_file)
32
- load @config_file
33
- colorset = self.colorit( group, Groupings )
34
- end
31
+ colorset = Array.new
32
+ colorset = self.colorit( group )
35
33
  return colorset
36
34
  end
37
35
 
@@ -40,6 +38,10 @@ module ColorTail
40
38
  puts " * #{group}"
41
39
  end
42
40
  end
41
+
42
+ def group_exists?(key)
43
+ Groupings.has_key?(key) ? true : false
44
+ end
43
45
  end
44
46
 
45
47
  class ComplexRecord < StandardError
@@ -65,6 +67,11 @@ module ColorTail
65
67
  o.on( '-g', '--group <group>', 'Specify the color grouping to use for these files' ) do |group|
66
68
  options[:group] = group
67
69
  end
70
+
71
+ options[:filename_prefix] = false
72
+ o.on( '-F', '--filename_prefix', 'Prefix each colored line with it\'s filename') do
73
+ options[:filename_prefix] = true
74
+ end
68
75
 
69
76
  options[:list] = false
70
77
  o.on( '-l', '--list', 'List all the available color groupings' ) do |group|
@@ -81,11 +88,26 @@ module ColorTail
81
88
  raise FileDoesNotExist, "Config file #{file} cannot be found."
82
89
  end
83
90
  end
91
+
92
+ o.on('-V', '--version', "Display version information") do
93
+ options[:version] = true
94
+ end
84
95
 
85
96
  options[:help] = false
86
- o.on_tail( '-h', '--help', 'Display this help screen' ) do
97
+ o.on( '-h', '--help', 'Display this help screen' ) do
87
98
  options[:help] = true
88
99
  end
100
+
101
+ o.separator ""
102
+ o.separator "Examples:"
103
+ o.separator " Tail messages and mail log through STDIN with syslog group:"
104
+ o.separator " cat /var/log/maillog | #{File.basename($0)} -g syslog /var/log/messages"
105
+
106
+ o.separator " Tail messages with syslog group and maillog with mail group:"
107
+ o.separator " #{File.basename($0)} /var/log/messages#syslog /var/log/messages#mail"
108
+
109
+ o.separator " Tail messages with syslog group and maillog with mail group with line prefix:"
110
+ o.separator " #{File.basename($0)} -F /var/log/messages#syslog /var/log/messages#mail"
89
111
  end
90
112
 
91
113
  begin
@@ -38,6 +38,18 @@ module TestColortail
38
38
  end
39
39
  end
40
40
 
41
+ context "With '-V' option and no files" do
42
+ setup do
43
+ ARGV.clear
44
+ ARGV.push("-V")
45
+ end
46
+
47
+ should "show the version string" do
48
+ ColorTail::Application.run!(*ARGV)
49
+ assert_match /.*\ v/, $stderr.string
50
+ end
51
+ end
52
+
41
53
  context "With '-h' option and no files" do
42
54
  setup do
43
55
  ARGV.clear
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: colortail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Lubow
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-04-26 00:00:00 -04:00
12
+ date: 2010-05-09 00:00:00 -04:00
13
13
  default_executable: colortail
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency