simple_structured_logger 0.1.5 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd3c01ed526e586a28acf3c9dcc9c3d8220bea4547c264568cf32c4293c9a77c
4
- data.tar.gz: dc3beaa6509ca46fb2be4405e6211b75b373f87221dca5f7ba66e25ed723c4a2
3
+ metadata.gz: 824ec497606b6c639fdc7209c9854243512457bb7b97bc3ae3b6300354f85916
4
+ data.tar.gz: 56bdbf5858c33164a08ec88ee96cb0842c8f11a2caeef1123af14f3a2b0a73f7
5
5
  SHA512:
6
- metadata.gz: 9a1a5ba635be779a15ea83a4d17d8e71af96f0dc5cc0324bc2ac83af8e76fb959047d236b9e1191990481dfeaaf390469c0b737bfbc532f3bc24fe4979cdf636
7
- data.tar.gz: 94830ac9e6452c82183564f9a67e58560d9eacd617a7aea1d69c1d291ffc4187da7726c386895361f78da3e1faa4f020c12c452ac4b01e639c1cbf06bf13a1c2
6
+ metadata.gz: 8296498d2355f715ccc7a8b089f3129ed39688ebb8503e940f1b729d18d754142878524c48f3ab9cc8221910be0ea6200259ad9c1b1d4fa994f8e2dcab363ad2
7
+ data.tar.gz: 384a55748e300dcc7903be2609094af12fd88a4e2d3c58abf5646fb819314e9cb68b034c25890c2562355fe26babcd89fc422d617fd3373dff255ff0dc6b9ab9
@@ -0,0 +1,59 @@
1
+ name: "CodeQL"
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ # The branches below must be a subset of the branches above
8
+ branches: [ master ]
9
+ schedule:
10
+ - cron: '24 16 * * 1'
11
+
12
+ jobs:
13
+ analyze:
14
+ name: Analyze
15
+ runs-on: ubuntu-latest
16
+ permissions:
17
+ actions: read
18
+ contents: read
19
+ security-events: write
20
+
21
+ strategy:
22
+ fail-fast: false
23
+ matrix:
24
+ language: [ 'ruby' ]
25
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
26
+ # Learn more about CodeQL language support at https://git.io/codeql-language-support
27
+
28
+ steps:
29
+ - name: Checkout repository
30
+ uses: actions/checkout@v2
31
+
32
+ # Initializes the CodeQL tools for scanning.
33
+ - name: Initialize CodeQL
34
+ uses: github/codeql-action/init@v1
35
+ with:
36
+ languages: ${{ matrix.language }}
37
+ # If you wish to specify custom queries, you can do so here or in a config file.
38
+ # By default, queries listed here will override any specified in a config file.
39
+ # Prefix the list here with "+" to use these queries and those in the config file.
40
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
41
+
42
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
43
+ # If this step fails, then you should remove it and run the build manually (see below)
44
+ - name: Autobuild
45
+ uses: github/codeql-action/autobuild@v1
46
+
47
+ # ℹ️ Command-line programs to run using the OS shell.
48
+ # 📚 https://git.io/JvXDl
49
+
50
+ # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
51
+ # and modify them (or add more) to build your code if your project
52
+ # uses a compiled language
53
+
54
+ #- run: |
55
+ # make bootstrap
56
+ # make release
57
+
58
+ - name: Perform CodeQL Analysis
59
+ uses: github/codeql-action/analyze@v1
@@ -19,15 +19,15 @@ jobs:
19
19
  runs-on: ubuntu-latest
20
20
  strategy:
21
21
  matrix:
22
- ruby-version: ['2.6', '2.7', '3.0']
22
+ ruby-version: ['2.6', '2.7', '3.0', '3.1']
23
23
 
24
24
  steps:
25
25
  - uses: actions/checkout@v2
26
26
  - name: Set up Ruby
27
- uses: ruby/setup-ruby@v1
27
+ uses: ruby/setup-ruby@v1
28
28
  with:
29
29
  ruby-version: ${{ matrix.ruby-version }}
30
30
  bundler-cache: true
31
31
  - name: Run tests
32
32
  run: bundle exec rake
33
-
33
+
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  /vendor/bundle
11
+ /*.gem
data/.tool-versions CHANGED
@@ -1 +1 @@
1
- ruby 2.7.3
1
+ ruby 3.1.1
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Michael Bianco
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -3,23 +3,107 @@
3
3
 
4
4
  # SimpleStructuredLogger
5
5
 
6
- Dead-simple structured logging in ruby with a dead-simple codebase. That's it.
6
+ Dead-simple structured logging in ruby with a dead-simple codebase. No dependencies, everything logs to stdout, and simple hooks to customize. That's it.
7
7
 
8
8
  ```ruby
9
9
  gem 'simple_structured_logger'
10
10
  ```
11
11
 
12
+ ## Usage
13
+
14
+ You can use this logger anywhere. Class methods, instance methods, use it as a logger for libraries, etc.
15
+
16
+ Some examples:
17
+
18
+ ```ruby
19
+ # in a console or simple script
20
+ include SimpleStructuredLogger
21
+ log.info 'core message', key: Time.now.to_i
22
+
23
+ # in class & instance methods
24
+ class LoggingInModule
25
+ include SimpleStructuredLogger
26
+
27
+ def self.log_something
28
+ log.info 'including the module enables a class and instance method', key: Time.now.to_i
29
+ end
30
+
31
+ def log_something_else
32
+ log.info 'the class and instance method share the same logging context', key: Time.now.to_i
33
+ end
34
+ end
35
+
36
+ # So, how do I set the context? How can I customize how it's set?
37
+ SimpleStructuredLogger.configure do
38
+ expand_context do |context|
39
+ # you can pass in a object and use `expand_context` to extract the relevant keys
40
+ if context[:user]
41
+ context[:user_id] = context[:user].id
42
+ context[:user_name] = context[:user].name
43
+ end
44
+
45
+ context
46
+ end
47
+ end
48
+
49
+ class ExampleJob
50
+ def perform(user_id)
51
+ user = get_user(user_id, job_argument)
52
+ log.set_context(user: user, job: self.class, job_argument: job_argument)
53
+ log.info 'the log will contain the user_id, job_argument, and job class'
54
+
55
+ # you can also add additional default pairs without resetting context
56
+ log.default_tags[:something] = 'else'
57
+ end
58
+ end
59
+
60
+ # Can you pass object arguments as values and automatically expand them? Well, yes, you can!
61
+ SimpleStructuredLogger.configure do
62
+ expand_log do |tags, default_tags|
63
+ if tags[:stripe_resource] && tags[:stripe_resource].respond_to?(:id)
64
+ stripe_resource = tags.delete(:stripe_resource)
65
+ tags[:stripe_resource_id] = stripe_resource.id
66
+ tags[:stripe_resource_type] = stripe_resource.class.to_s
67
+ end
68
+
69
+ # this is a really nice pattern I like to use. The `metric` key can trigger a call out to your observability tooling
70
+ if tags[:metric]
71
+ dimensions = default_tags.slice(:stripe_user_id, :other_default_tag)
72
+ metrics.track_counter(tags[:metric], dimensions: dimensions)
73
+ end
74
+
75
+ tags
76
+ end
77
+ end
78
+
79
+ # want simple formatting? You got it!
80
+ SimpleStructuredLogger.logger.formatter = proc do |severity, _datetime, _progname, msg|
81
+ "#{severity}: #{msg}\n"
82
+ end
83
+
84
+ # Configure the logger directly if you need to
85
+ SimpleStructuredLogger.logger.level(Logger::INFO)
86
+ ```
87
+
88
+ Want to change the log level quickly? Without modifying source?
89
+
90
+ ```shell
91
+ LOG_LEVEL=DEBUG ruby your_script.rb
92
+
93
+ # case does not matter
94
+ LOG_LEVEL=info ruby your_script.rb
95
+ ```
96
+
12
97
  ## Design Goals
13
98
 
14
99
  * Extremely simple codebase that's easy to read and override
15
- * Structured logging that reads nicely
100
+ * Structured logging that reads nicely and is easy to filter using grep or something like Papertrail
16
101
  * Ability to easily set context, and expand context with user-configurable hook
17
102
  * Ability to easily add structured log pre-processing. I want to be able to pass
18
- in an object specific to my application and for the relavent important keys to
103
+ in an object specific to my application and for the relevant important keys to
19
104
  be expanded automatically.
20
105
  * `Rails.logger = SimpleStructuredLogger.new(STDOUT)`
21
- * Not designed around massive systems or scale
22
- * Don't support multiple log destinations
106
+ * Not designed around massive systems or scale: no JSON logging, multiple log destinations, and other fanciness.
23
107
  * Don't build in fancy pre-processing for errors or other common ruby objects
24
108
 
25
109
  ### Opinionated Devops Setup
@@ -37,6 +121,10 @@ gem 'simple_structured_logger'
37
121
  * https://github.com/nishidayuya/structured_logger
38
122
  * https://github.com/rocketjob/semantic_logger
39
123
 
124
+ ## Related
125
+
126
+ * https://github.com/roidrage/lograge
127
+
40
128
  ## Why is structured logging important?
41
129
 
42
130
  * https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying
@@ -45,33 +133,14 @@ gem 'simple_structured_logger'
45
133
  ## What about Rail's tagged logging?
46
134
 
47
135
  Tagged logging is not structured logging. I want to be able to search through
48
- PaperTrail and easily grab an audit trail for a specific context, i.e. `the_job=FailingJob the_user=1`.
49
-
50
- ## Usage
51
-
52
- ```ruby
53
- # config/initializers/logger.rb
54
- if Rails.env.development? || Rails.env.test?
55
- SimpleStructuredLogger::Writer.instance.logger = Rails.logger
56
- end
57
-
58
- # models/order.rb
59
- class Order
60
- include SimpleStructuredLogger
61
-
62
- def initialize
63
- log.reset_context!
64
- log.default_tags[:global] = 'key'
65
- end
66
-
67
- def do_something
68
- log.info 'simple structured logging', key: value, shopify_id: 123
69
- end
70
- end
71
- ```
136
+ PaperTrail/Splunk/etc and easily grab an audit trail for a specific context, i.e. `the_job=FailingJob the_user=1`.
72
137
 
73
138
  ## Testing
74
139
 
75
140
  ```
76
141
  bundle exec rake
77
142
  ```
143
+
144
+ ## TODO
145
+
146
+ - [ ] Support logs as blocks?
@@ -2,6 +2,14 @@ require 'logger'
2
2
  require 'singleton'
3
3
 
4
4
  module SimpleStructuredLogger
5
+ def self.configure(&block)
6
+ SimpleStructuredLogger::Configuration.instance_eval(&block)
7
+ end
8
+
9
+ def self.logger
10
+ SimpleStructuredLogger::Writer.instance.logger
11
+ end
12
+
5
13
  def log
6
14
  SimpleStructuredLogger::Writer.instance
7
15
  end
@@ -13,25 +21,27 @@ module SimpleStructuredLogger
13
21
  SimpleStructuredLogger::Writer.instance
14
22
  end
15
23
  end
16
-
17
24
  end
18
25
 
19
26
  module Configuration
20
27
  extend self
21
28
 
29
+ @expand_context = nil
30
+ @expand_log = nil
31
+
22
32
  def expand_context(&block)
23
33
  if block.nil?
24
- @expand_context = block
25
- else
26
34
  @expand_context
35
+ else
36
+ @expand_context = block
27
37
  end
28
38
  end
29
39
 
30
40
  def expand_log(&block)
31
41
  if block.nil?
32
- @expand_log = block
33
- else
34
42
  @expand_log
43
+ else
44
+ @expand_log = block
35
45
  end
36
46
  end
37
47
  end
@@ -44,6 +54,16 @@ module SimpleStructuredLogger
44
54
  def initialize
45
55
  @logger = ::Logger.new(STDOUT)
46
56
  @default_tags = {}
57
+
58
+ set_log_level_from_environment
59
+ end
60
+
61
+ def set_log_level_from_environment
62
+ env_log_level = ENV['LOG_LEVEL']
63
+
64
+ if !env_log_level.nil? && Logger::Severity.const_defined?(env_log_level.upcase)
65
+ @logger.level = Logger::Severity.const_get(env_log_level.upcase)
66
+ end
47
67
  end
48
68
 
49
69
  def reset_context!
@@ -53,8 +73,8 @@ module SimpleStructuredLogger
53
73
  def set_context(context)
54
74
  reset_context!
55
75
 
56
- if self.respond_to?(:expand_context)
57
- context = self.expand_context(context)
76
+ if SimpleStructuredLogger::Configuration.expand_context
77
+ context = SimpleStructuredLogger::Configuration.expand_context.call(context)
58
78
  end
59
79
 
60
80
  @default_tags.merge!(context)
@@ -73,26 +93,18 @@ module SimpleStructuredLogger
73
93
  end
74
94
 
75
95
  def warn(msg, opts={})
76
- # TODO consider returning the generated log string with structured keys
77
-
78
96
  @logger.warn("#{msg}: #{stringify_tags(opts)}")
79
97
  end
80
98
 
81
- private
99
+ private def stringify_tags(additional_tags)
100
+ additional_tags = additional_tags.dup
82
101
 
83
- def generate_log(msg, opts)
84
- #code
102
+ if SimpleStructuredLogger::Configuration.expand_log
103
+ additional_tags = SimpleStructuredLogger::Configuration.expand_log.call(additional_tags, self.default_tags)
85
104
  end
86
105
 
87
- def stringify_tags(additional_tags)
88
- additional_tags = additional_tags.dup
89
-
90
- if self.respond_to?(:expand_log)
91
- additional_tags = self.expand_log(additional_tags)
92
- end
93
-
94
- @default_tags.merge(additional_tags).map { |k,v| "#{k}=#{v}" }.join(' ')
95
- end
106
+ @default_tags.merge(additional_tags).map {|k, v| "#{k}=#{v}" }.join(' ')
107
+ end
96
108
 
97
109
  end
98
110
  end
@@ -4,20 +4,19 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "simple_structured_logger"
7
- spec.version = '0.1.5'
7
+ spec.version = '1.0.0'
8
8
  spec.authors = ["Michael Bianco"]
9
9
  spec.email = ["mike@mikebian.co"]
10
+ spec.licenses = ['MIT']
10
11
 
11
- spec.summary = "Dead-simple structured logging in ruby with a simple codebase."
12
- # spec.description = %q{TODO: Write a longer description or delete this line.}
12
+ spec.summary = "Dead-simple structured logging in ruby with a simple codebase"
13
13
  spec.homepage = "https://github.com/iloveitaly/simple_structured_logger"
14
14
 
15
15
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
- spec.bindir = "exe"
17
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
16
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
17
  spec.require_paths = ["lib"]
19
18
 
20
- spec.add_development_dependency "bundler", "~> 2.2.15"
21
- spec.add_development_dependency "rake", "~> 12.3.3"
22
- spec.add_development_dependency "minitest", "~> 5.0"
19
+ spec.add_development_dependency "bundler", "~> 2.3.10"
20
+ spec.add_development_dependency "rake", "~> 13.0.6"
21
+ spec.add_development_dependency "minitest", "~> 5.15"
23
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_structured_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bianco
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-05 00:00:00.000000000 Z
11
+ date: 2022-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,54 +16,58 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 2.2.15
19
+ version: 2.3.10
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 2.2.15
26
+ version: 2.3.10
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 12.3.3
33
+ version: 13.0.6
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 12.3.3
40
+ version: 13.0.6
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '5.0'
47
+ version: '5.15'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '5.0'
54
+ version: '5.15'
55
55
  description:
56
56
  email:
57
57
  - mike@mikebian.co
58
- executables: []
58
+ executables:
59
+ - console
60
+ - setup
59
61
  extensions: []
60
62
  extra_rdoc_files: []
61
63
  files:
62
64
  - ".github/dependabot.yml"
65
+ - ".github/workflows/codeql-analysis.yml"
63
66
  - ".github/workflows/ruby.yml"
64
67
  - ".gitignore"
65
68
  - ".tool-versions"
66
69
  - Gemfile
70
+ - LICENSE
67
71
  - README.md
68
72
  - Rakefile
69
73
  - bin/console
@@ -71,7 +75,8 @@ files:
71
75
  - lib/simple_structured_logger.rb
72
76
  - simple_structured_logger.gemspec
73
77
  homepage: https://github.com/iloveitaly/simple_structured_logger
74
- licenses: []
78
+ licenses:
79
+ - MIT
75
80
  metadata: {}
76
81
  post_install_message:
77
82
  rdoc_options: []
@@ -88,8 +93,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
93
  - !ruby/object:Gem::Version
89
94
  version: '0'
90
95
  requirements: []
91
- rubygems_version: 3.1.6
96
+ rubygems_version: 3.3.7
92
97
  signing_key:
93
98
  specification_version: 4
94
- summary: Dead-simple structured logging in ruby with a simple codebase.
99
+ summary: Dead-simple structured logging in ruby with a simple codebase
95
100
  test_files: []