google_logger 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6d992358263779aad83ebfcc34161a69d2ccad81ac6dba67dd36ac110a2b5d3c
4
+ data.tar.gz: 34612d6398a35047a3bba53fc83f59afd0ea58b84226c8b60f2c572c63a6b3df
5
+ SHA512:
6
+ metadata.gz: d54e6e687f4afb7059bb366b198cd53ffc8a19882a88dda84d39efbd637eb77fced4a963a2df7c76e39612e5d9b2469eab8740b74f1c327fcb906863a5c19272
7
+ data.tar.gz: 11509739cfacf03d16a94722b63527d6d971c8ffd3b0be3df9c95d25026e45ff8c917c112aacfd90d94ca0c8e27eb57f0d7288a5e06b863aa72188e7f3a39f56
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stackdriver'
4
+ require 'google_logger/version'
5
+ require 'google_logger/configuration'
6
+ require 'google_logger/loggers/cloud_logger'
7
+ require 'google_logger/loggers/local_logger'
8
+ require 'google_logger/loggers/base'
9
+ require 'google_logger/controller_logging'
10
+ require 'google_logger/params_replacer'
11
+
12
+ # Main module which should serve as an interface to all functionalities
13
+ module GoogleLogger
14
+ class Error < StandardError; end
15
+
16
+ class InvalidConfigurationError < Error; end
17
+
18
+ class << self
19
+ attr_writer :configuration
20
+
21
+ # Returns GoogleLogger configuration
22
+ #
23
+ # @return [GoogleLogger::Configuration] current GoogleLogger configuration
24
+ def configuration
25
+ @configuration ||= Configuration.new
26
+ end
27
+
28
+ # Yields the cofiguration class
29
+ #
30
+ # @yield [GoogleLogger::Configuration] current GoogleLogger configuration
31
+ #
32
+ # @return [GoogleLogger::Configuration] GoogleLogger configuration with assigned values
33
+ def configure
34
+ yield(configuration) if block_given?
35
+
36
+ configuration.validate!
37
+
38
+ configuration
39
+ end
40
+
41
+ # Creates a new entry
42
+ #
43
+ # @param [String, Hash] payload content of the log
44
+ # @param [String] log_name log_name which can be used to filter logs
45
+ # @param [Symbol] severity severity of the log
46
+ #
47
+ # return [Boolean] `true` if the entry was successfully written
48
+ def create_entry(payload, log_name: 'default_log', severity: :DEFAULT)
49
+ logger_instance = logger
50
+ entry = logger_instance.build_entry(payload, log_name: log_name, severity: severity)
51
+ logger_instance.write_entry(entry)
52
+ end
53
+
54
+ # Creates a new entry for an exception which includes exception message, class and backtrace
55
+ #
56
+ # @param [StandardError] exception exception to be logged
57
+ #
58
+ # return [Boolean] `true` if the entry was successfully written
59
+ def log_exception(exception)
60
+ payload = {
61
+ message: exception.message,
62
+ exception: exception.class.name,
63
+ bactrace: exception.backtrace&.first(5)
64
+ }
65
+
66
+ create_entry(payload, log_name: 'error', severity: :ERROR)
67
+ rescue StandardError => e
68
+ log_google_logger_error(e)
69
+ end
70
+
71
+ # Creates a new entry for a controller request, the entry includes params,
72
+ # request URL, client ip address and http method
73
+ #
74
+ # @param [ActionDispatch::Request] request request to be logged
75
+ # @param [ActionController::StrongParameters] params parameters to be logged
76
+ #
77
+ # return [Boolean] `true` if the entry was successfully written
78
+ def log_request(request, params)
79
+ payload = {
80
+ params: params,
81
+ original_url: request.original_url,
82
+ ip: request.ip,
83
+ method: request.method
84
+ }
85
+
86
+ create_entry(payload, log_name: 'request', severity: :INFO)
87
+ rescue StandardError => e
88
+ log_google_logger_error(e)
89
+ end
90
+
91
+ # Returns the currently used logger
92
+ #
93
+ # @return [Object] GoogleLogger::Logger by default, local logger if `loc_locally` is set to true
94
+ def logger
95
+ if configuration.log_locally
96
+ Loggers::LocalLogger.new
97
+ else
98
+ Loggers::CloudLogger.new
99
+ end
100
+ end
101
+
102
+ # Log gem errors locally if local_logger is present
103
+ #
104
+ # @param [StandardError] exception the error that will be logged
105
+ def log_google_logger_error(exception)
106
+ local_logger = GoogleLogger.configuration.local_logger
107
+ local_logger.error "GOOGLE_LOGGER ERROR: #{exception.inspect}" if local_logger.present?
108
+ end
109
+
110
+ def deep_replace_secret_params(params)
111
+ ParamsReplacer.deep_replace_secret_params(params)
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GoogleLogger
4
+ class Configuration
5
+ attr_accessor(*%i[
6
+ async
7
+ resource_type
8
+ resource_labels
9
+ secret_params
10
+ secret_param_value
11
+ project_id
12
+ credentials
13
+ log_locally
14
+ local_logger
15
+ ])
16
+
17
+ # Creates a new instance with default configuration values
18
+ def initialize
19
+ @async = true
20
+ @resource_type = 'gae_app'
21
+ @resource_labels = {}
22
+ @secret_params = %i[password]
23
+ @secret_param_value = '<SECRET_PARAM>'
24
+ @log_locally = false
25
+ end
26
+
27
+ def validate!
28
+ if @log_locally
29
+ validate_local_logger
30
+ else
31
+ validate_credentials
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def validate_local_logger
38
+ raise_invalid!('"local_logger" must be provided if "log_locally" is set to "true"') if local_logger.nil?
39
+
40
+ log_levels = GoogleLogger::Loggers::LocalLogger::SEVERITY_MAPPING.values.uniq + [:unknown]
41
+
42
+ # make sure the logger responds to logger methods
43
+ log_levels.each do |log_level|
44
+ raise_invalid!("\"local_logger\" must respond to \"#{log_level}\"") unless local_logger.respond_to?(log_level)
45
+ end
46
+ end
47
+
48
+ def validate_credentials
49
+ return unless @project_id.nil? || @project_id == '' || @credentials.nil? || @credentials == ''
50
+
51
+ raise_invalid!('"project_id" and "credentials" cannot be blank')
52
+ end
53
+
54
+ def raise_invalid!(message)
55
+ raise InvalidConfigurationError, message
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+
5
+ module GoogleLogger
6
+ module ControllerLogging
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ protected
11
+
12
+ # Logs the request and any uncaught exceptions, acts as an `around_action` filter.
13
+ # Exceptions are propagated so that they can be caught in the application.
14
+ def log_request_to_google
15
+ GoogleLogger.log_request(request, google_log_params)
16
+ yield
17
+ rescue StandardError => e
18
+ GoogleLogger.log_exception(e)
19
+ raise
20
+ end
21
+
22
+ # Returns params which should be logged, secret params have their value hidden before being logged
23
+ #
24
+ # @return [Hash] params hash with secret values hidden
25
+ def google_log_params
26
+ params_to_log = params.to_unsafe_h
27
+ GoogleLogger.deep_replace_secret_params(params_to_log)
28
+ params_to_log
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GoogleLogger
4
+ module Loggers
5
+ class Base
6
+ protected
7
+
8
+ def configuration
9
+ GoogleLogger.configuration
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base'
4
+
5
+ module GoogleLogger
6
+ module Loggers
7
+ class CloudLogger < Base
8
+ # Creates a new logger with project_id and credentials specified in configuration
9
+ def initialize
10
+ @project = Google::Cloud::Logging.new(
11
+ project_id: configuration.project_id,
12
+ credentials: configuration.credentials
13
+ )
14
+ end
15
+
16
+ # Builds a new entry
17
+ #
18
+ # @param [String, Hash] payload content of the log
19
+ # @param [String] log_name log_name which can be used to filter logs
20
+ # @param [Symbol] severity severity of the log
21
+ #
22
+ # @return [Google::Cloud::Logging::Entry] entry with payload and default resource configuration
23
+ def build_entry(payload, log_name: 'default_log', severity: :DEFAULT)
24
+ entry = @project.entry(payload: payload, log_name: log_name, severity: severity, timestamp: Time.now)
25
+ entry.resource.type = configuration.resource_type
26
+ entry.resource.labels = configuration.resource_labels
27
+ entry
28
+ end
29
+
30
+ # Writes an entry to google cloud
31
+ #
32
+ # @param [Google::Cloud::Logging::Entry] entry entry to be written to google cloud
33
+ # defaults to configuration value
34
+ #
35
+ # return [Boolean] `true` if the entry was successfully written
36
+ def write_entry(entry)
37
+ log_writer = configuration.async ? @project : @project.async_writer
38
+ log_writer.write_entries(entry)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base'
4
+
5
+ module GoogleLogger
6
+ module Loggers
7
+ class LocalLogger < Base
8
+ SEVERITY_MAPPING = {
9
+ DEFAULT: :info,
10
+ DEBUG: :debug,
11
+ INFO: :info,
12
+ NOTICE: :info,
13
+ WARNING: :warn,
14
+ ERROR: :error,
15
+ CRITICAL: :fatal,
16
+ ALERT: :fatal,
17
+ EMERGENCY: :fatal
18
+ }.freeze
19
+
20
+ # Builds a new entry
21
+ #
22
+ # @param [String, Hash] payload content of the log
23
+ # @param [Hash] entry_args arguments which would normally be passed to google entry
24
+ #
25
+ # @return [Hash] entry with payload and default resource configuration
26
+ def build_entry(payload, entry_args = {})
27
+ entry_args[:payload] = payload
28
+ entry_args
29
+ end
30
+
31
+ # Writes an entry to google cloud
32
+ #
33
+ # @param [Hash] entry entry to be written to google cloud
34
+ #
35
+ # return [Boolean] `true` if the entry was successfully written
36
+ def write_entry(entry)
37
+ log_level = SEVERITY_MAPPING[entry[:severity]] || :unknown
38
+ configuration.local_logger.public_send(log_level, entry.inspect)
39
+
40
+ true
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GoogleLogger
4
+ class ParamsReplacer
5
+ def deep_replace_secret_params(arg)
6
+ case arg
7
+ when Hash
8
+ deep_replace_params_in_hash(arg)
9
+ when Array
10
+ deep_replace_params_in_array(arg)
11
+ end
12
+ end
13
+
14
+ def deep_replace_params_in_hash(hash)
15
+ hash.each do |key, value|
16
+ if GoogleLogger.configuration.secret_params.include?(key.to_sym)
17
+ hash[key] = GoogleLogger.configuration.secret_param_value
18
+ else
19
+ deep_replace_secret_params(value)
20
+ end
21
+ end
22
+ end
23
+
24
+ def deep_replace_params_in_array(array)
25
+ array.each { |item| deep_replace_secret_params(item) }
26
+ end
27
+
28
+ class << self
29
+ delegate :deep_replace_secret_params, to: :new
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GoogleLogger
4
+ VERSION = '1.0.0'
5
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: google_logger
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jan Hric
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-07-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.4.5
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 5.2.4.5
27
+ - !ruby/object:Gem::Dependency
28
+ name: stackdriver
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.21.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.21.1
41
+ description: |-
42
+ Provides convenient methods to log all controller requests
43
+ and also provides a wrapper class which simplifies custom logging.
44
+ email:
45
+ - hric95@seznam.cz
46
+ executables: []
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - lib/google_logger.rb
51
+ - lib/google_logger/configuration.rb
52
+ - lib/google_logger/controller_logging.rb
53
+ - lib/google_logger/loggers/base.rb
54
+ - lib/google_logger/loggers/cloud_logger.rb
55
+ - lib/google_logger/loggers/local_logger.rb
56
+ - lib/google_logger/params_replacer.rb
57
+ - lib/google_logger/version.rb
58
+ homepage: https://github.com/panter/google_logger
59
+ licenses:
60
+ - MIT
61
+ metadata:
62
+ homepage_uri: https://github.com/panter/google_logger
63
+ source_code_uri: https://github.com/panter/google_logger
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ - lib/google_logger
69
+ - lib/google_logger/loggers
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 2.5.0
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.7.6.2
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Provides a simple interface to write logs to the google cloud platform.
86
+ test_files: []