summaryrefslogtreecommitdiff
path: root/lib/leap_cli/logger.rb
blob: 989a548ee8f1a863253b565045b13088e67e13dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#
# A drop in replacement for Capistrano::Logger that integrates better with LEAP CLI.
#

require 'capistrano/logger'

#
# from Capistrano::Logger
# =========================
#
# IMPORTANT = 0
# INFO      = 1
# DEBUG     = 2
# TRACE     = 3
# MAX_LEVEL = 3
# COLORS = {
#   :none     => "0",
#   :black    => "30",
#   :red      => "31",
#   :green    => "32",
#   :yellow   => "33",
#   :blue     => "34",
#   :magenta  => "35",
#   :cyan     => "36",
#   :white    => "37"
# }
# STYLES = {
#   :bright     => 1,
#   :dim        => 2,
#   :underscore => 4,
#   :blink      => 5,
#   :reverse    => 7,
#   :hidden     => 8
# }
#

module LeapCli
  class Logger < Capistrano::Logger

    def initialize(options={})
      @options = options
      @level = options[:level] || 0
    end

    def log(level, message, line_prefix=nil, options={})
      # formatting modifies message & line_prefix, so create dups
      message = message.dup
      options = options.dup
      if !line_prefix.nil?
        if !line_prefix.is_a?(String)
          line_prefix = line_prefix.to_s.dup
        else
          line_prefix = line_prefix.dup
        end
      end
      options[:level] ||= level

      # apply formatting
      apply_formatting(message, line_prefix, options)

      # print message
      if options[:level] <= self.level
        message.lines.each do |line|
          line = line.strip
          line_prefix = line_prefix.strip if line_prefix
          if line.chars.any?
            if line_prefix
              LeapCli::log "[#{line_prefix}] #{line}"
            else
              LeapCli::log line
            end
          end
        end
      end
    end

    private

    ##
    ## FORMATTING
    ##

    @formatters = [
      # TRACE
      { :match => /command finished/,          :color => :white,   :style => :dim, :match_level => 3, :priority => -10 },
      { :match => /executing locally/,         :color => :yellow,  :match_level => 3, :priority => -20 },

      # DEBUG
      #{ :match => /executing .*/,             :color => :green,   :match_level => 2, :priority => -10, :timestamp => true },
      #{ :match => /.*/,                        :color => :yellow,  :match_level => 2, :priority => -30 },
      { :match => /^transaction:/,             :level => 3 },

      # INFO
      { :match => /.*out\] (fatal:|ERROR:).*/, :color => :red,     :match_level => 1, :priority => -10 },
      { :match => /Permission denied/,         :color => :red,     :match_level => 1, :priority => -20 },
      { :match => /sh: .+: command not found/, :color => :magenta, :match_level => 1, :priority => -30 },

      # IMPORTANT
      { :match => /^err ::/,                   :color => :red,     :match_level => 0, :priority => -10 },
      { :match => /.*/,                        :color => :blue,    :match_level => 0, :priority => -20 },

      # PREFIX CLEANUP
      { :match => /(err|out) :: /,             :replace => '', :priority => 0},

      # DEBIAN PACKAGES
      { :match => /^(Hit|Ign) /,                :color => :green,   :priority => -20},
      { :match => /^Err /,                      :color => :red,     :priority => -20},
      { :match => /^W: /,                       :color => :yellow,  :priority => -20},
      { :match => /already the newest version/, :color => :green,   :priority => -20},

      # PUPPPET
      { :match => /^warning: .*is deprecated.*$/,  :level => 2, :color => :yellow, :priority => -10},
      { :match => /^notice:/,                      :level => 1, :color => :cyan,   :priority => -20},
      { :match => /^err:/,                         :level => 0, :color => :red,    :priority => -20},
      { :match => /^warning:/,                     :level => 0, :color => :yellow, :priority => -20},
      { :match => /Finished catalog run/,          :level => 0, :color => :green,  :priority => -10},
    ]

    def apply_formatting(message, line_prefix = nil, options={})
      color = options[:color] || :none
      style = options[:style]
      continue = true
      self.class.sorted_formatters.each do |formatter|
        break unless continue
        if (formatter[:match_level] == level || formatter[:match_level].nil?)
          [message, line_prefix].compact.each do |str|
            if str =~ formatter[:match]
              options[:level] = formatter[:level] if formatter[:level]
              color = formatter[:color] if formatter[:color]
              style = formatter[:style] || formatter[:attribute] # (support original cap colors)

              str.gsub!(formatter[:match], formatter[:replace]) if formatter[:replace]
              str.replace(formatter[:prepend] + str) unless formatter[:prepend].nil?
              str.replace(str + formatter[:append])  unless formatter[:append].nil?
              str.replace(Time.now.strftime('%Y-%m-%d %T') + ' ' + str) if formatter[:timestamp]

              # stop formatting, unless formatter was just for string replacement
              continue = false unless formatter[:replace]
            end
          end
        end
      end

      return if color == :hide
      return if color == :none && style.nil?

      term_color = COLORS[color]
      term_style = STYLES[style]
      if line_prefix.nil?
        message.replace format(message, term_color, term_style)
      else
        line_prefix.replace format(line_prefix, term_color, term_style)
      end
    end

  end
end