Class: SemanticLogger::Appender::Http

Inherits:
Subscriber
  • Object
show all
Defined in:
lib/semantic_logger/appender/http.rb

Direct Known Subclasses

ElasticsearchHttp, Loki, SplunkHttp, Metric::Signalfx

Instance Attribute Summary collapse

Attributes inherited from Subscriber

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

Instance Method Summary collapse

Methods inherited from Subscriber

#close, #console_output?, #console_stream, #flush, #level, #should_log?

Constructor Details

#initialize(url:, compress: false, ssl: {}, username: nil, password: nil, header: {}, proxy_url: :ENV, open_timeout: 2.0, read_timeout: 1.0, continue_timeout: 1.0, **args) ⇒ Http

Create HTTP(S) log appender

Parameters:

url: [String]
Valid URL to post to.
  Example: http://example.com/some_path
To enable SSL include https in the URL.
  Example: https://example.com/some_path
  verify_mode will default: OpenSSL::SSL::VERIFY_PEER

application: [String]
Name of this application to appear in log messages.
Default: SemanticLogger.application

host: [String]
Name of this host to appear in log messages.
Default: SemanticLogger.host

username: [String]
User name for basic Authentication.
Default: nil ( do not use basic auth )

password: [String]
Password for basic Authentication.

header: [Hash]
Custom HTTP headers to send with each request.
Default: {} ( do not send any custom headers)
Example: {"Authorization" => "Bearer BEARER_TOKEN"}

compress: [true|false]
Whether to compress the JSON string with GZip.
Default: false

ssl: [Hash]
Specific SSL options: For more details see NET::HTTP.start
  ca_file, ca_path, cert, cert_store, ciphers, key, ssl_timeout,
  ssl_version, verify_callback, verify_depth and verify_mode.

proxy_url: [String]
URL of proxy server to use for HTTP(s) connections.  Should
  include username and password if required.
  Example: http://user@pass:example.com/some_path
To enable SSL include https in the URL.
  Example: https://example.com/some_path
If this is set to :ENV, Net::HTTP will use the environment http_proxy*
  variables if they are set.  If set to nil then no proxy will be used,
  even if the environment variables are set.

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

formatter: [Object|Proc]
An instance of a class that implements #call, or a Proc to be used to format
the output from this appender
Default: Use the built-in formatter (See: #call)

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.

open_timeout: [Float]
Default: 2.0

read_timeout: [Float]
Default: 1.0

continue_timeout: [Float]
Default: 1.0


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
158
159
160
161
162
163
164
165
166
# File 'lib/semantic_logger/appender/http.rb', line 108

def initialize(url:,
               compress: false,
               ssl: {},
               username: nil,
               password: nil,
               header: {},
               proxy_url: :ENV,
               open_timeout: 2.0,
               read_timeout: 1.0,
               continue_timeout: 1.0,
               **args,
               &)
  @url              = url
  @proxy_url        = proxy_url
  @ssl_options      = ssl
  @username         = username
  @password         = password
  @compress         = compress
  @open_timeout     = open_timeout
  @read_timeout     = read_timeout
  @continue_timeout = continue_timeout

  # On Ruby v2.0 and greater, Net::HTTP.new already uses a persistent connection if the server allows it
  @header = {
    "Accept"       => "application/json",
    "Content-Type" => "application/json",
    "Connection"   => "keep-alive",
    "Keep-Alive"   => "300"
  }.merge(header)
  @header["Content-Encoding"] = "gzip" if @compress

  uri     = URI.parse(@url)
  @server = uri.host
  unless @server
    raise(ArgumentError, "Invalid format for :url: #{@url.inspect}. Should be similar to: 'http://hostname:port/path'")
  end

  @port     = uri.port
  @username = uri.user if !@username && uri.user
  @password = uri.password if !@password && uri.password
  @path     = uri.path
  # Path cannot be empty
  @path     = "/" if @path == ""

  if uri.scheme == "https"
    @ssl_options[:use_ssl] = true
    @ssl_options[:verify_mode] ||= OpenSSL::SSL::VERIFY_PEER
    @port                      ||= HTTP.https_default_port
  else
    @port ||= HTTP.http_default_port
  end

  @proxy_uri = URI.parse(@proxy_url) if @proxy_url && @proxy_url != :ENV

  @http = nil

  super(**args, &)
  reopen
end

Instance Attribute Details

#compressObject

Returns the value of attribute compress.



32
33
34
# File 'lib/semantic_logger/appender/http.rb', line 32

def compress
  @compress
end

#continue_timeoutObject

Returns the value of attribute continue_timeout.



32
33
34
# File 'lib/semantic_logger/appender/http.rb', line 32

def continue_timeout
  @continue_timeout
end

#headerObject

Returns the value of attribute header.



32
33
34
# File 'lib/semantic_logger/appender/http.rb', line 32

def header
  @header
end

#httpObject (readonly)

Returns the value of attribute http.



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

def http
  @http
end

#open_timeoutObject

Returns the value of attribute open_timeout.



32
33
34
# File 'lib/semantic_logger/appender/http.rb', line 32

def open_timeout
  @open_timeout
end

#pathObject (readonly)

Returns the value of attribute path.



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

def path
  @path
end

#portObject (readonly)

Returns the value of attribute port.



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

def port
  @port
end

#proxy_urlObject (readonly)

Returns the value of attribute proxy_url.



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

def proxy_url
  @proxy_url
end

#read_timeoutObject

Returns the value of attribute read_timeout.



32
33
34
# File 'lib/semantic_logger/appender/http.rb', line 32

def read_timeout
  @read_timeout
end

#serverObject (readonly)

Returns the value of attribute server.



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

def server
  @server
end

#ssl_optionsObject (readonly)

Returns the value of attribute ssl_options.



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

def ssl_options
  @ssl_options
end

#urlObject (readonly)

Returns the value of attribute url.



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

def url
  @url
end

#usernameObject

Returns the value of attribute username.



32
33
34
# File 'lib/semantic_logger/appender/http.rb', line 32

def username
  @username
end

Instance Method Details

#batch(logs) ⇒ Object

Forward a batch of log messages to the HTTP Server in a single request. Only used when the appender is created with batch: true.



206
207
208
209
210
# File 'lib/semantic_logger/appender/http.rb', line 206

def batch(logs)
  message = formatter.batch(logs, self)
  logger.trace(message)
  post(message)
end

#batch_by_default?Boolean

The HTTP appender supports batching, but only when explicitly requested via batch: true, so that the default behaviour (one request per log message) is preserved.

Returns:

  • (Boolean)


215
216
217
# File 'lib/semantic_logger/appender/http.rb', line 215

def batch_by_default?
  false
end

#log(log) ⇒ Object

Forward log messages to HTTP Server



198
199
200
201
202
# File 'lib/semantic_logger/appender/http.rb', line 198

def log(log)
  message = formatter.call(log, self)
  logger.trace(message)
  post(message)
end

#reopenObject

Re-open after process fork



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/semantic_logger/appender/http.rb', line 169

def reopen
  # Close open connection if any
  begin
    @http&.finish
  rescue IOError
    nil
  end

  @http = if @proxy_uri
            Net::HTTP.new(server, port, @proxy_uri.host, @proxy_uri.port, @proxy_uri.user, @proxy_uri.password)
          else
            Net::HTTP.new(server, port, @proxy_url)
          end

  if @ssl_options
    @http.methods.grep(/\A(\w+)=\z/) do |meth|
      key = Regexp.last_match(1).to_sym
      @ssl_options.key?(key) || next
      @http.__send__(meth, @ssl_options[key])
    end
  end

  @http.open_timeout     = @open_timeout
  @http.read_timeout     = @read_timeout
  @http.continue_timeout = @continue_timeout
  @http.start
end