Class: SemanticLogger::Appender::Syslog

Inherits:
Subscriber show all
Defined in:
lib/semantic_logger/appender/syslog.rb

Instance Attribute Summary collapse

Attributes inherited from Subscriber

#application, #formatter, #host, #logger, #metrics

Attributes inherited from Base

#filter, #name

Instance Method Summary collapse

Methods inherited from Subscriber

#close, #level, #should_log?

Methods inherited from Base

#backtrace, #fast_tag, #level, #level=, #measure, #payload, #pop_tags, #push_tags, #should_log?, #silence, #tagged, #tags, #with_payload

Constructor Details

#initialize(url: 'syslog://localhost', facility: ::Syslog::LOG_USER, level_map: SemanticLogger::Formatters::Syslog::LevelMap.new, options: ::Syslog::LOG_PID | ::Syslog::LOG_CONS, tcp_client: {}, **args, &block) ⇒ Syslog

Create a Syslog appender instance.

Parameters

url: [String]
  Default: 'syslog://localhost'
  For writing logs to a remote syslog server
  URL of server: protocol://host:port
  Uses port 514 by default for TCP and UDP.
  local syslog example:          'syslog://localhost'
  TCP example with default port: 'tcp://logger'
  TCP example with custom port:  'tcp://logger:8514'
  UDP example with default port: 'udp://logger'
  UDP example with custom port:  'udp://logger:8514'
  When using the :syslog protocol, logs will always be sent to the localhost syslog

host: [String]
  Host name to provide to the remote syslog.
  Default: SemanticLogger.host

tcp_client: [Hash]
  Default: {}
  Only used with the TCP protocol.
  Specify custom parameters to pass into Net::TCPClient.new
  For a list of options see the net_tcp_client documentation:
    https://github.com/rocketjob/net_tcp_client/blob/master/lib/net/tcp_client/tcp_client.rb

level: [:trace | :debug | :info | :warn | :error | :fatal]
  Override the log level for this appender.
  Default: SemanticLogger.default_level

filter: [Regexp|Proc]
  RegExp: Only include log messages where the class name matches the supplied.
  regular expression. All other messages will be ignored.
  Proc: Only include log messages where the supplied Proc returns true
        The Proc must return true or false.

application: [String]
  Identity of the program.
  Default: SemanticLogger.application

options: [Integer]
  Default: ::Syslog::LOG_PID | ::Syslog::LOG_CONS
  Any of the following (options can be logically OR'd together)
    ::Syslog::LOG_CONS
    ::Syslog::LOG_NDELAY
    ::Syslog::LOG_NOWAIT
    ::Syslog::LOG_ODELAY
    ::Syslog::LOG_PERROR
    ::Syslog::LOG_PID
 Note:
   - Only applicable when logging to a local syslog instance.
     I.e. When `url: 'syslog://localhost'`

facility: [Integer]
  Default: ::Syslog::LOG_USER
  Type of program (can be logically OR'd together)
    ::Syslog::LOG_AUTH
    ::Syslog::LOG_AUTHPRIV
    ::Syslog::LOG_CONSOLE
    ::Syslog::LOG_CRON
    ::Syslog::LOG_DAEMON
    ::Syslog::LOG_FTP
    ::Syslog::LOG_KERN
    ::Syslog::LOG_LRP
    ::Syslog::LOG_MAIL
    ::Syslog::LOG_NEWS
    ::Syslog::LOG_NTP
    ::Syslog::LOG_SECURITY
    ::Syslog::LOG_SYSLOG
    ::Syslog::LOG_USER
    ::Syslog::LOG_UUCP
    ::Syslog::LOG_LOCAL0
    ::Syslog::LOG_LOCAL1
    ::Syslog::LOG_LOCAL2
    ::Syslog::LOG_LOCAL3
    ::Syslog::LOG_LOCAL4
    ::Syslog::LOG_LOCAL5
    ::Syslog::LOG_LOCAL6
    ::Syslog::LOG_LOCAL7

level_map: [Hash | SemanticLogger::Formatters::Syslog::LevelMap]
  Supply a custom map of SemanticLogger levels to syslog levels.

Example:
  # Change the warn level to LOG_NOTICE level instead of a the default of LOG_WARNING.
  SemanticLogger.add_appender(appender: :syslog, level_map: {warn: ::Syslog::LOG_NOTICE})


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
158
159
160
161
162
163
# File 'lib/semantic_logger/appender/syslog.rb', line 122

def initialize(url: 'syslog://localhost',
               facility: ::Syslog::LOG_USER,
               level_map: SemanticLogger::Formatters::Syslog::LevelMap.new,
               options: ::Syslog::LOG_PID | ::Syslog::LOG_CONS,
               tcp_client: {},
               **args,
               &block)

  @options            = options
  @facility           = facility
  @level_map          = level_map
  @url                = url
  uri                 = URI(@url)
  @server             = uri.host || 'localhost'
  @protocol           = (uri.scheme || :syslog).to_sym
  @port               = uri.port || 514
  @server             = 'localhost' if @protocol == :syslog
  @tcp_client_options = tcp_client

  raise "Unknown protocol #{@protocol}!" unless %i[syslog tcp udp].include?(@protocol)

  # The syslog_protocol gem is required when logging over TCP or UDP.
  if %i[tcp udp].include?(@protocol)
    begin
      require 'syslog_protocol'
    rescue LoadError
      raise 'Missing gem: syslog_protocol. This gem is required when logging over TCP or UDP. To fix this error: gem install syslog_protocol'
    end

    # The net_tcp_client gem is required when logging over TCP.
    if protocol == :tcp
      begin
        require 'net/tcp_client'
      rescue LoadError
        raise 'Missing gem: net_tcp_client. This gem is required when logging over TCP. To fix this error: gem install net_tcp_client'
      end
    end
  end

  super(**args, &block)
  reopen
end

Instance Attribute Details

#facilityObject (readonly)

Returns the value of attribute facility.



34
35
36
# File 'lib/semantic_logger/appender/syslog.rb', line 34

def facility
  @facility
end

#level_mapObject (readonly)

Returns the value of attribute level_map.



34
35
36
# File 'lib/semantic_logger/appender/syslog.rb', line 34

def level_map
  @level_map
end

#optionsObject (readonly)

Returns the value of attribute options.



34
35
36
# File 'lib/semantic_logger/appender/syslog.rb', line 34

def options
  @options
end

#portObject (readonly)

Returns the value of attribute port.



34
35
36
# File 'lib/semantic_logger/appender/syslog.rb', line 34

def port
  @port
end

#protocolObject (readonly)

Returns the value of attribute protocol.



34
35
36
# File 'lib/semantic_logger/appender/syslog.rb', line 34

def protocol
  @protocol
end

#remote_syslogObject (readonly)

Returns the value of attribute remote_syslog.



34
35
36
# File 'lib/semantic_logger/appender/syslog.rb', line 34

def remote_syslog
  @remote_syslog
end

#serverObject (readonly)

Returns the value of attribute server.



34
35
36
# File 'lib/semantic_logger/appender/syslog.rb', line 34

def server
  @server
end

#urlObject (readonly)

Returns the value of attribute url.



34
35
36
# File 'lib/semantic_logger/appender/syslog.rb', line 34

def url
  @url
end

Instance Method Details

#default_formatterObject

Returns [SemanticLogger::Formatters::Base] default formatter for this Appender depending on the protocal selected



207
208
209
210
211
212
213
214
# File 'lib/semantic_logger/appender/syslog.rb', line 207

def default_formatter
  if protocol == :syslog
    # Format is text output without the time
    SemanticLogger::Formatters::Default.new(time_format: nil)
  else
    SemanticLogger::Formatters::Syslog.new(facility: facility, level_map: level_map)
  end
end

#flushObject

Flush is called by the semantic_logger during shutdown.



202
203
204
# File 'lib/semantic_logger/appender/syslog.rb', line 202

def flush
  @remote_syslog.flush if @remote_syslog&.respond_to?(:flush)
end

#log(log) ⇒ Object

Write the log using the specified protocol and server.



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/semantic_logger/appender/syslog.rb', line 185

def log(log)
  case @protocol
  when :syslog
    # Since the Ruby Syslog API supports sprintf format strings, double up all existing '%'
    message = formatter.call(log, self).gsub '%', '%%'
    ::Syslog.log @level_map[log.level], message
  when :tcp
    @remote_syslog.retry_on_connection_failure { @remote_syslog.write("#{formatter.call(log, self)}\r\n") }
  when :udp
    @remote_syslog.send(formatter.call(log, self), 0, @server, @port)
  else
    raise "Unsupported protocol: #{protocol}"
  end
  true
end

#reopenObject

After forking an active process call #reopen to re-open open the handles to resources



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/semantic_logger/appender/syslog.rb', line 167

def reopen
  case @protocol
  when :syslog
    method = ::Syslog.opened? ? :reopen : :open
    ::Syslog.send(method, application, options, facility)
  when :tcp
    # Use the local logger for @remote_syslog so errors with the remote logger can be recorded locally.
    @tcp_client_options[:logger] = logger
    @tcp_client_options[:server] = "#{@server}:#{@port}"
    @remote_syslog               = Net::TCPClient.new(@tcp_client_options)
  when :udp
    @remote_syslog = UDPSocket.new
  else
    raise "Unsupported protocol: #{@protocol}"
  end
end