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, #environment, #formatter, #host, #logger, #metrics

Attributes inherited from Base

#filter, #name

Instance Method Summary collapse

Methods inherited from Subscriber

#close, #console_output?, #level, #should_log?

Methods inherited from Base

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

Constructor Details

#initialize(url: "syslog://localhost", facility: ::Syslog::LOG_USER, max_size: 1024, 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/reidmorrison/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

max_size: [Integer]
  Set your own packet size.
  Default: 1024 bytes

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})


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
164
165
166
167
168
169
170
171
# File 'lib/semantic_logger/appender/syslog.rb', line 126

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

  @options            = options
  @facility           = facility
  @max_size           = max_size
  @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 LoadError,
            "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 LoadError,
              "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

#max_sizeObject (readonly)

Returns the value of attribute max_size.



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

def max_size
  @max_size
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



215
216
217
218
219
220
221
222
# File 'lib/semantic_logger/appender/syslog.rb', line 215

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, max_size: max_size)
  end
end

#flushObject

Flush is called by the semantic_logger during shutdown.



210
211
212
# File 'lib/semantic_logger/appender/syslog.rb', line 210

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

#log(log) ⇒ Object

Write the log using the specified protocol and server.



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/semantic_logger/appender/syslog.rb', line 193

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



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/semantic_logger/appender/syslog.rb', line 175

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