simple_structured_logger 0.1.4 → 1.0.1

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
- SHA1:
3
- metadata.gz: 450b49d293e7743eaa62f2beb6c27cb3e02dea41
4
- data.tar.gz: 8d8cc75dabd6c182f445f002e6724cc55d22bf74
2
+ SHA256:
3
+ metadata.gz: 959e1a8479e4536b7c1a97cca00e409b4d979e611a5da6a214311cb33a877070
4
+ data.tar.gz: 555fd1aa0f22f2470b65e724bdaf861d1f28ece8fd5d9decf8579bd7bcd4d7b1
5
5
  SHA512:
6
- metadata.gz: 83c99c8d4e03fbaba09731d2fb9f41d565b3ad89575ca7b79ff216781b079dad94aedc9b84e7f35f30e3d86d5a377107085a040395e5826c1a6371995709f7f6
7
- data.tar.gz: 9ef9a6dd5774733c7badfb042a1c800ce52a25428f8b49f0f9e474d94eb92c2d91e6e2d19ec9cd46a471bf453f0806757efc7d78da82b1624153fd05cab15513
6
+ metadata.gz: 87bc3367c2993374dbb3c2220a6d9378cfecaf0480901e26f305850b75c7584ea7a90cbe8c1c9bc831802e07456bf50a250a03a0cb2634faa926e6f9523e770f
7
+ data.tar.gz: '0489971ce5a5d82e1a9b3327510a322796ba4b02014300f286502df17923bfe35de572d272119647a32edcd97798409ef68be0ea8fe62d1e93c033758a0633f5'
@@ -0,0 +1,7 @@
1
+ # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
2
+ version: 2
3
+ updates:
4
+ - package-ecosystem: "bundler"
5
+ directory: "/" # Location of package manifests
6
+ schedule:
7
+ interval: "monthly"
@@ -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
@@ -0,0 +1,33 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ master ]
13
+ pull_request:
14
+ branches: [ master ]
15
+
16
+ jobs:
17
+ test:
18
+
19
+ runs-on: ubuntu-latest
20
+ strategy:
21
+ matrix:
22
+ ruby-version: ['2.6', '2.7', '3.0', '3.1']
23
+
24
+ steps:
25
+ - uses: actions/checkout@v2
26
+ - name: Set up Ruby
27
+ uses: ruby/setup-ruby@v1
28
+ with:
29
+ ruby-version: ${{ matrix.ruby-version }}
30
+ bundler-cache: true
31
+ - name: Run tests
32
+ run: bundle exec rake
33
+
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  /vendor/bundle
11
+ /*.gem
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.1.1
data/Gemfile CHANGED
@@ -1,4 +1,2 @@
1
1
  source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in simple_structured_logger.gemspec
4
2
  gemspec
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
@@ -1,22 +1,109 @@
1
+ [![Ruby](https://github.com/iloveitaly/simple_structured_logger/actions/workflows/ruby.yml/badge.svg)](https://github.com/iloveitaly/simple_structured_logger/actions/workflows/ruby.yml)
2
+ [![gem](https://img.shields.io/gem/v/simple_structured_logger.svg)](https://rubygems.org/gems/simple_structured_logger)
3
+
1
4
  # SimpleStructuredLogger
2
5
 
3
- 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.
4
7
 
5
8
  ```ruby
6
9
  gem 'simple_structured_logger'
7
10
  ```
8
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
+
9
97
  ## Design Goals
10
98
 
11
99
  * Extremely simple codebase that's easy to read and override
12
- * Structured logging that reads nicely
100
+ * Structured logging that reads nicely and is easy to filter using grep or something like Papertrail
13
101
  * Ability to easily set context, and expand context with user-configurable hook
14
102
  * Ability to easily add structured log pre-processing. I want to be able to pass
15
- 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
16
104
  be expanded automatically.
17
105
  * `Rails.logger = SimpleStructuredLogger.new(STDOUT)`
18
- * Not designed around massive systems or scale
19
- * Don't support multiple log destinations
106
+ * Not designed around massive systems or scale: no JSON logging, multiple log destinations, and other fanciness.
20
107
  * Don't build in fancy pre-processing for errors or other common ruby objects
21
108
 
22
109
  ### Opinionated Devops Setup
@@ -34,6 +121,10 @@ gem 'simple_structured_logger'
34
121
  * https://github.com/nishidayuya/structured_logger
35
122
  * https://github.com/rocketjob/semantic_logger
36
123
 
124
+ ## Related
125
+
126
+ * https://github.com/roidrage/lograge
127
+
37
128
  ## Why is structured logging important?
38
129
 
39
130
  * https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying
@@ -42,33 +133,14 @@ gem 'simple_structured_logger'
42
133
  ## What about Rail's tagged logging?
43
134
 
44
135
  Tagged logging is not structured logging. I want to be able to search through
45
- PaperTrail and easily grab an audit trail for a specific context, i.e. `the_job=FailingJob the_user=1`.
46
-
47
- ## Usage
48
-
49
- ```ruby
50
- # config/initializers/logger.rb
51
- if Rails.env.development? || Rails.env.test?
52
- SimpleStructuredLogger::Writer.instance.logger = Rails.logger
53
- end
54
-
55
- # models/order.rb
56
- class Order
57
- include SimpleStructuredLogger
58
-
59
- def initialize
60
- log.reset_context!
61
- log.default_tags[:global] = 'key'
62
- end
63
-
64
- def do_something
65
- log.info 'simple structured logging', key: value, shopify_id: 123
66
- end
67
- end
68
- ```
136
+ PaperTrail/Splunk/etc and easily grab an audit trail for a specific context, i.e. `the_job=FailingJob the_user=1`.
69
137
 
70
138
  ## Testing
71
139
 
72
140
  ```
73
141
  bundle exec rake
74
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,20 @@ 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
+ # returns true if log level is set from env
62
+ def set_log_level_from_environment
63
+ env_log_level = ENV['LOG_LEVEL']
64
+
65
+ if !env_log_level.nil? && Logger::Severity.const_defined?(env_log_level.upcase)
66
+ @logger.level = Logger::Severity.const_get(env_log_level.upcase)
67
+ true
68
+ else
69
+ false
70
+ end
47
71
  end
48
72
 
49
73
  def reset_context!
@@ -53,8 +77,8 @@ module SimpleStructuredLogger
53
77
  def set_context(context)
54
78
  reset_context!
55
79
 
56
- if self.respond_to?(:expand_context)
57
- context = self.expand_context(context)
80
+ if SimpleStructuredLogger::Configuration.expand_context
81
+ context = SimpleStructuredLogger::Configuration.expand_context.call(context)
58
82
  end
59
83
 
60
84
  @default_tags.merge!(context)
@@ -73,26 +97,18 @@ module SimpleStructuredLogger
73
97
  end
74
98
 
75
99
  def warn(msg, opts={})
76
- # TODO consider returning the generated log string with structured keys
77
-
78
100
  @logger.warn("#{msg}: #{stringify_tags(opts)}")
79
101
  end
80
102
 
81
- private
103
+ private def stringify_tags(additional_tags)
104
+ additional_tags = additional_tags.dup
82
105
 
83
- def generate_log(msg, opts)
84
- #code
106
+ if SimpleStructuredLogger::Configuration.expand_log
107
+ additional_tags = SimpleStructuredLogger::Configuration.expand_log.call(additional_tags, self.default_tags)
85
108
  end
86
109
 
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
110
+ @default_tags.merge(additional_tags).map {|k, v| "#{k}=#{v}" }.join(' ')
111
+ end
96
112
 
97
113
  end
98
114
  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.4'
7
+ spec.version = '1.0.1'
8
8
  spec.authors = ["Michael Bianco"]
9
- spec.email = ["mike@cliffsidemedia.com"]
9
+ spec.email = ["mike@mikebian.co"]
10
+ spec.licenses = ['MIT']
10
11
 
11
- spec.summary = "Dead-simple structured logging in ruby with a dead-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", "~> 1.11"
21
- spec.add_development_dependency "rake", "~> 10.0"
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.4
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bianco
8
- autorequire:
9
- bindir: exe
8
+ autorequire:
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-24 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,51 +16,58 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.11'
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: '1.11'
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: '10.0'
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: '10.0'
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'
55
- description:
54
+ version: '5.15'
55
+ description:
56
56
  email:
57
- - mike@cliffsidemedia.com
58
- executables: []
57
+ - mike@mikebian.co
58
+ executables:
59
+ - console
60
+ - setup
59
61
  extensions: []
60
62
  extra_rdoc_files: []
61
63
  files:
64
+ - ".github/dependabot.yml"
65
+ - ".github/workflows/codeql-analysis.yml"
66
+ - ".github/workflows/ruby.yml"
62
67
  - ".gitignore"
68
+ - ".tool-versions"
63
69
  - Gemfile
70
+ - LICENSE
64
71
  - README.md
65
72
  - Rakefile
66
73
  - bin/console
@@ -68,9 +75,10 @@ files:
68
75
  - lib/simple_structured_logger.rb
69
76
  - simple_structured_logger.gemspec
70
77
  homepage: https://github.com/iloveitaly/simple_structured_logger
71
- licenses: []
78
+ licenses:
79
+ - MIT
72
80
  metadata: {}
73
- post_install_message:
81
+ post_install_message:
74
82
  rdoc_options: []
75
83
  require_paths:
76
84
  - lib
@@ -85,9 +93,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
93
  - !ruby/object:Gem::Version
86
94
  version: '0'
87
95
  requirements: []
88
- rubyforge_project:
89
- rubygems_version: 2.5.1
90
- signing_key:
96
+ rubygems_version: 3.3.7
97
+ signing_key:
91
98
  specification_version: 4
92
- summary: Dead-simple structured logging in ruby with a dead-simple codebase.
99
+ summary: Dead-simple structured logging in ruby with a simple codebase
93
100
  test_files: []