class SemanticLogger::Appender::Http

def compress_data(data)

def compress_data(data)
  str = StringIO.new
  gz  = Zlib::GzipWriter.new(str)
  gz << data
  gz.close
  str.string
end

def default_formatter

Use JSON Formatter by default
def default_formatter
  SemanticLogger::Formatters::Json.new
end

def delete(request_uri = path)

HTTP Delete
def delete(request_uri = path)
  request = Net::HTTP::Delete.new(request_uri, @header)
  process_request(request)
end

def initialize(url:,

Default: 1.0
continue_timeout: [Float]

Default: 1.0
read_timeout: [Float]

Default: 2.0
open_timeout: [Float]

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

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

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

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

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

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

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

Password for basic Authentication.
password: [String]

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

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

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

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

Create HTTP(S) log appender
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,
               &block)
  @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, &block)
  reopen
end

def log(log)

Forward log messages to HTTP Server
def log(log)
  message = formatter.call(log, self)
  logger.trace(message)
  post(message)
end

def post(body, request_uri = path)

HTTP Post
def post(body, request_uri = path)
  request = Net::HTTP::Post.new(request_uri, @header)
  process_request(request, body)
end

def process_request(request, body = nil)

Process HTTP Request
def process_request(request, body = nil)
  if body
    request.body = compress ? compress_data(body) : body
  end
  request.basic_auth(@username, @password) if @username
  response = @http.request(request)
  if response.is_a?(Net::HTTPSuccess)
    true
  else
    # Failures are logged to the global semantic logger failsafe logger (Usually stderr or file)
    logger.error("Bad HTTP response from: #{url} code: #{response.code}, #{response.body}")
    false
  end
rescue RuntimeError => e
  reopen
  raise e
end

def put(body, request_uri = path)

HTTP Put
def put(body, request_uri = path)
  request = Net::HTTP::Put.new(request_uri, @header)
  process_request(request, body)
end

def reopen

Re-open after process fork
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