rails_loki_exporter 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f11bbef4b6c0211c1df8c50080abc4b9854cad8cc25cc8f50d475ae00e38241a
4
- data.tar.gz: 6543c6c82ea8c379aabef263cd19ce18e74b3ad1751dd9c5932a12292334f43a
3
+ metadata.gz: bce248aa49394ba911efadd30695bc1d71a19ea2e8cd9909099339a4cb2bc5eb
4
+ data.tar.gz: c744a44f2bd0ee8f01391d0a2b8da796bc84ff71fad4ac8d1cbf7b5d95c12fc3
5
5
  SHA512:
6
- metadata.gz: dcde3cc9ce2aa6f8ae02bbdabfd28626a5b95e6be56009223051c72755aa8dd8c53b7cf0cac8103c00bf5f1faa6c373842398d993f15ec4655a36b6312ba13ac
7
- data.tar.gz: b41d24af30d8eb94e8c7fc16c93f410ae49e3db638e915748315e3eda5628424e9edfa405a57e00c5371910d17b0528361faff0c92d681aa47cea51b5a663a01
6
+ metadata.gz: 40491ac4ac77da177c05f445ad2e31332535f4784654aaeebf78d81eb1ec15e45f5ad8db6306a955b47e67d887574f22cefcd7efac8759bcd4b050f05ecb3c90
7
+ data.tar.gz: 5a5d1ec7f81b184cee101091a3330c6f7c6d31d300681f6028d28e113bb732aa8cf2690aaf99dae689218f9c473bea2c5585299a11f48fe12fa42541bddf7bd6
@@ -8,7 +8,7 @@ module RailsLokiExporter
8
8
  class InterceptingLogger < ActiveSupport::Logger
9
9
  attr_accessor :client
10
10
 
11
- SEVERITY_NAMES = %w(DEBUG INFO WARN ERROR FATAL).freeze
11
+ SEVERITY_NAMES = %w(DEBUG INFO WARN ERROR FATAL ANY).freeze
12
12
 
13
13
  def initialize(intercept_logs: false)
14
14
  @intercept_logs = intercept_logs
@@ -23,37 +23,18 @@ module RailsLokiExporter
23
23
  if log_message.nil?
24
24
  if block_given?
25
25
  log_message = yield
26
- end
27
- end
28
-
29
- if @intercept_logs
30
- if log_message.nil?
31
- puts caller
32
26
  else
33
- client.send_log(@log) if client
27
+ log_message = progname
28
+ progname = @progname
34
29
  end
35
30
  end
36
- super(severity, message, progname, &block)
37
- end
38
-
39
- def debug(log_message = "")
40
- client.send_log("#{log_message}") if client
41
- end
42
31
 
43
- def info(log_message = "")
44
- client.send_log("#{log_message}") if client
45
- end
46
-
47
- def fatal(log_message = "")
48
- client.send_log("#{log_message}") if client
49
- end
50
-
51
- def warn(log_message = "")
52
- client.send_log("#{log_message}") if client
53
- end
32
+ if @intercept_logs && !log_message.nil?
33
+ formatted_message = format_message(severity_name, Time.now, progname, log_message)
34
+ client.send_log(formatted_message) if client
35
+ end
54
36
 
55
- def error(log_message = "")
56
- client.send_log("#{log_message}") if client
37
+ super(severity, message, progname, &block)
57
38
  end
58
39
 
59
40
  def broadcast_to(console)
@@ -0,0 +1,121 @@
1
+ require 'socket'
2
+ require 'json'
3
+ require 'net/http'
4
+ require 'uri'
5
+
6
+ module RailsLokiExporter
7
+ LOGS_TYPE = %w(ERROR WARN FATAL INFO DEBUG).freeze
8
+
9
+ class LokiHttpClient
10
+
11
+ def initialize(config)
12
+ uri = URI.parse(config['base_url'])
13
+ @base_url = uri
14
+ @log_file_path = config['log_file_path']
15
+ @logs_type = config['logs_type']
16
+ @intercept_logs = config['intercept_logs']
17
+ @job_name = config['job_name'] || "#{$0}_#{Process.pid}"
18
+ @host_name = config['host_name'] || Socket.gethostname
19
+ @user_name = config['user_name']
20
+ @password = config['password']
21
+ @auth_enabled = config['auth_enabled']
22
+ @log_buffer = []
23
+ @last_interaction_time = nil
24
+ @interaction_interval = 1 # in seconds, adjust as needed
25
+ @max_buffer_size = 10 # set the maximum number of logs to buffer
26
+
27
+ http = Net::HTTP.new(@base_url.to_s, @base_url.port)
28
+ http.use_ssl = @base_url.scheme == 'https'
29
+ http.read_timeout = 30
30
+ http.open_timeout = 30
31
+ http
32
+ end
33
+
34
+ def send_log(log_message)
35
+ @log_buffer << log_message
36
+ if @log_buffer.size >= @max_buffer_size || can_send_log?
37
+ send_buffered_logs
38
+ @last_interaction_time = Time.now
39
+ else
40
+ # @logger.info('Log buffered. Waiting for more logs or interaction interval.')
41
+ end
42
+ end
43
+
44
+ private
45
+ def send_buffered_logs
46
+ return if @log_buffer.empty?
47
+
48
+ curr_datetime = Time.now.to_i * 1_000_000_000
49
+ msg = "On server #{@host_name} detected error"
50
+ payload = {
51
+ 'streams' => [
52
+ { 'stream' => {
53
+ 'job' => @job_name,
54
+ 'host' => @host_name },
55
+ 'values' => @log_buffer.map { |log| [curr_datetime.to_s, log] }}
56
+ ]
57
+ }
58
+
59
+ json_payload = JSON.generate(payload)
60
+ uri = '/loki/api/v1/push'
61
+ post(uri, json_payload)
62
+
63
+ @log_buffer.clear
64
+ end
65
+
66
+ def can_send_log?
67
+ return true if @last_interaction_time.nil?
68
+
69
+ elapsed_time = Time.now - @last_interaction_time
70
+ elapsed_time >= @interaction_interval
71
+ end
72
+
73
+ def match_logs_type?(log_line)
74
+ return false if log_line.nil?
75
+
76
+ type_match = log_line.match(/(ERROR|WARN|FATAL|INFO|DEBUG)/)
77
+ type = type_match ? type_match.to_s : 'UNMATCHED'
78
+ type == 'UNMATCHED' || @logs_type.include?(type)
79
+ end
80
+
81
+ def post(url_loki, body)
82
+ url = @base_url.to_s + url_loki
83
+ username = @user_name
84
+ password = @password
85
+ send_authenticated_post(url, body, username, password)
86
+ end
87
+
88
+ def send_authenticated_post(url, body, username, password)
89
+ uri = URI.parse(url)
90
+ request = Net::HTTP::Post.new(uri.path)
91
+ request['Content-Type'] = 'application/json'
92
+ request.body = body
93
+
94
+ if username && password && @auth_enabled
95
+ request.basic_auth(username, password)
96
+ else
97
+ raise "Username or password is nil."
98
+ end
99
+ response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
100
+ http.request(request)
101
+ end
102
+
103
+ case response
104
+ when Net::HTTPSuccess
105
+ response.body ? JSON.parse(response.body) : nil
106
+ when Net::HTTPNoContent
107
+ puts "Request successful, but no content was returned."
108
+ nil
109
+ else
110
+ raise "Failed to make POST request. Response code: #{response.code}, Response body: #{response.body}"
111
+ end
112
+ rescue StandardError => e
113
+ puts "Error: #{e.message}"
114
+ end
115
+
116
+ def base64_encode_credentials(user_name, password)
117
+ credentials = "#{user_name}:#{password}"
118
+ Base64.strict_encode64(credentials)
119
+ end
120
+ end
121
+ end
@@ -1,3 +1,3 @@
1
1
  module RailsLokiExporter
2
- VERSION = '1.0.3'
2
+ VERSION = '1.0.4'
3
3
  end
@@ -7,23 +7,12 @@ module RailsLokiExporter
7
7
  class << self
8
8
  def create_logger(config_file_path)
9
9
  config = load_config(config_file_path)
10
-
11
- connection_instance = MyConnection.new(
12
- config['base_url'],
13
- config['user_name'],
14
- config['password'],
15
- config['auth_enabled'],
16
- config['host_name'],
17
- config['job_name']
18
- )
19
-
20
- client = Client.new(config)
10
+ client = LokiHttpClient.new(config)
21
11
  logger = InterceptingLogger.new(intercept_logs: config['intercept_logs'])
22
12
  if config['enable_log_subscriber']
23
13
  CustomLogSubscriber.client = client
24
14
  end
25
15
  logger.client = client
26
- client.connection = connection_instance
27
16
  logger
28
17
  end
29
18
 
@@ -35,7 +24,6 @@ module RailsLokiExporter
35
24
  if File.exist?(expanded_path)
36
25
  config_erb = ERB.new(File.read(expanded_path)).result
37
26
  config = YAML.safe_load(config_erb, aliases: true)
38
- puts config.to_json
39
27
  return config
40
28
  else
41
29
  puts "Config file not found: #{expanded_path}"
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_loki_exporter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - planning.how
8
8
  - Oleg Ten
9
9
  - Assiya Kalykova
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-02-03 00:00:00.000000000 Z
13
+ date: 2024-03-04 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: zeitwerk
@@ -52,19 +52,16 @@ files:
52
52
  - Gemfile
53
53
  - README.md
54
54
  - lib/rails_loki_exporter.rb
55
- - lib/rails_loki_exporter/client.rb
56
- - lib/rails_loki_exporter/connection.rb
57
55
  - lib/rails_loki_exporter/custom_log_subscriber.rb
58
56
  - lib/rails_loki_exporter/intercepting_logger.rb
59
- - lib/rails_loki_exporter/my_connection.rb
60
- - lib/rails_loki_exporter/query.rb
57
+ - lib/rails_loki_exporter/loki_http_client.rb
61
58
  - lib/rails_loki_exporter/version.rb
62
59
  - rails_loki_exporter.gemspec
63
60
  homepage: https://github.com/planninghow/rails-loki-exporter
64
61
  licenses:
65
62
  - MIT
66
63
  metadata: {}
67
- post_install_message:
64
+ post_install_message:
68
65
  rdoc_options: []
69
66
  require_paths:
70
67
  - lib
@@ -79,8 +76,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
79
76
  - !ruby/object:Gem::Version
80
77
  version: '0'
81
78
  requirements: []
82
- rubygems_version: 3.4.22
83
- signing_key:
79
+ rubygems_version: 3.1.6
80
+ signing_key:
84
81
  specification_version: 4
85
82
  summary: Rails Loki exporter
86
83
  test_files: []
@@ -1,92 +0,0 @@
1
- require 'socket'
2
- module RailsLokiExporter
3
- LOGS_TYPE = %w(ERROR WARN FATAL INFO DEBUG).freeze
4
-
5
- class Client
6
- include RailsLokiExporter::Connection
7
-
8
- attr_accessor :job_name
9
- attr_accessor :host_name
10
- attr_accessor :max_buffer_size
11
- attr_accessor :interaction_interval
12
- attr_accessor :connection
13
-
14
- def initialize(config)
15
- @base_url = config['base_url']
16
- @log_file_path = config['log_file_path']
17
- @logs_type = config['logs_type']
18
- @intercept_logs = config['intercept_logs']
19
- @job_name = config['job_name'] || "#{$0}_#{Process.pid}"
20
- @host_name = config['host_name'] || Socket.gethostname
21
- @log_buffer = []
22
- @last_interaction_time = nil
23
- @interaction_interval = 1 # in seconds, adjust as needed
24
- @max_buffer_size = 10 # set the maximum number of logs to buffer
25
- @connection = connection
26
- end
27
-
28
- def send_all_logs
29
- File.open(@log_file_path, 'r') do |file|
30
- file.each_line do |line|
31
- send_log(line)
32
- end
33
- end
34
- end
35
-
36
- def send_log(log_message)
37
- @log_buffer << log_message
38
- if @log_buffer.size >= @max_buffer_size || can_send_log?
39
- send_buffered_logs
40
- @last_interaction_time = Time.now
41
- else
42
- # @logger.info('Log buffered. Waiting for more logs or interaction interval.')
43
- end
44
- end
45
-
46
- private
47
- def send_buffered_logs
48
- return if @log_buffer.empty?
49
-
50
- curr_datetime = Time.now.to_i * 1_000_000_000
51
- msg = "On server #{@host_name} detected error"
52
- payload = {
53
- 'streams' => [
54
- {
55
- 'stream' => {
56
- 'job' => @job_name,
57
- 'host' => @host_name
58
- },
59
- 'values' => @log_buffer.map { |log| [curr_datetime.to_s, log] },
60
- 'entries' => @log_buffer.map do |_|
61
- {
62
- 'ts' => curr_datetime,
63
- 'line' => "[WARN] " + msg
64
- }
65
- end
66
- }
67
- ]
68
- }
69
-
70
- json_payload = JSON.generate(payload)
71
- uri = '/loki/api/v1/push'
72
- @connection.post(uri, json_payload)
73
-
74
- @log_buffer.clear
75
- end
76
-
77
- def can_send_log?
78
- return true if @last_interaction_time.nil?
79
-
80
- elapsed_time = Time.now - @last_interaction_time
81
- elapsed_time >= @interaction_interval
82
- end
83
-
84
- def match_logs_type?(log_line)
85
- return false if log_line.nil?
86
-
87
- type_match = log_line.match(/(ERROR|WARN|FATAL|INFO|DEBUG)/)
88
- type = type_match ? type_match.to_s : 'UNMATCHED'
89
- type == 'UNMATCHED' || @logs_type.include?(type)
90
- end
91
- end
92
- end
@@ -1,60 +0,0 @@
1
- require 'json'
2
- require 'net/http'
3
- require 'uri'
4
-
5
- module RailsLokiExporter
6
- module Connection
7
- def initialize(base_url, user_name, password, auth_enabled, host_name, job_name)
8
- uri = URI.parse(base_url)
9
- @base_url = uri
10
- @user_name = user_name
11
- @password = password
12
- @auth_enabled = auth_enabled
13
- end
14
- def connection
15
- http = Net::HTTP.new(@base_url.to_s, @base_url.port)
16
- http.use_ssl = @base_url.scheme == 'https'
17
- http.read_timeout = 30 # Adjust as needed
18
- http.open_timeout = 30 # Adjust as needed
19
- http
20
- end
21
- def post(url_loki, body)
22
- url = @base_url.to_s + url_loki
23
- username = @user_name
24
- password = @password
25
- send_authenticated_post(url, body, username, password)
26
- end
27
- def send_authenticated_post(url, body, username, password)
28
- uri = URI.parse(url)
29
- request = Net::HTTP::Post.new(uri.path)
30
- request['Content-Type'] = 'application/json'
31
- request.body = body
32
-
33
- if username && password && @auth_enabled
34
- request.basic_auth(username, password)
35
- else
36
- raise "Username or password is nil."
37
- end
38
-
39
- response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
40
- http.request(request)
41
- end
42
-
43
- case response
44
- when Net::HTTPSuccess
45
- response.body ? JSON.parse(response.body) : nil
46
- when Net::HTTPNoContent
47
- puts "Request successful, but no content was returned."
48
- nil
49
- else
50
- raise "Failed to make POST request. Response code: #{response.code}, Response body: #{response.body}"
51
- end
52
- rescue StandardError => e
53
- puts "Error: #{e.message}"
54
- end
55
- def base64_encode_credentials(user_name, password)
56
- credentials = "#{user_name}:#{password}"
57
- Base64.strict_encode64(credentials)
58
- end
59
- end
60
- end
@@ -1,8 +0,0 @@
1
- module RailsLokiExporter
2
- class MyConnection
3
- include Connection
4
- def self.create(base_url, user_name, password, auth_enabled, host_name, job_name)
5
- new(base_url, user_name, password, auth_enabled, host_name, job_name).connection
6
- end
7
- end
8
- end
@@ -1,8 +0,0 @@
1
- module RailsLokiExporter
2
- class Query
3
- attr_reader :streams_data
4
- def initialize(response)
5
- @streams_data = response['streams']
6
- end
7
- end
8
- end