lumberjack_data_dog 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 +7 -0
- data/.github/dependabot.yml +12 -0
- data/.github/workflows/continuous_integration.yml +46 -0
- data/.standard.yml +8 -0
- data/CHANGE_LOG.md +11 -0
- data/MIT_LICENSE.txt +20 -0
- data/README.md +148 -0
- data/VERSION +1 -0
- data/lib/lumberjack/data_dog.rb +144 -0
- data/lib/lumberjack_data_dog.rb +3 -0
- data/lumberjack_data_dog.gemspec +32 -0
- metadata +68 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 746fb699cb9f259ed561b070a1a3939573c052a2354cc7edbe7bf2b72084cf1e
|
4
|
+
data.tar.gz: 0647be2db0eac1df4c77ef89e5859396cd345a5b1291419a8ece171aff3bd48a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6232d656b9202c58b504c8eeb1a1904dbb85d06ed3d80d2e302d7cd0fd4657b2874685d3396e4b777ded9f7cd180fd1ddbbd1b192e78be0a160ac32b3806b4ce
|
7
|
+
data.tar.gz: '01209a5f00a204706e100cb6d389f5fac1b46f0ebe5ab39b12558c32811cf727813d5a1fe9b810599cd43d93b51182354a089e7de70e9d8312157c55b8aa7daf'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Dependabot update strategy
|
2
|
+
version: 2
|
3
|
+
updates:
|
4
|
+
- package-ecosystem: bundler
|
5
|
+
directory: "/"
|
6
|
+
schedule:
|
7
|
+
interval: weekly
|
8
|
+
allow:
|
9
|
+
# Automatically keep all runtime dependencies updated
|
10
|
+
- dependency-name: "*"
|
11
|
+
dependency-type: "production"
|
12
|
+
versioning-strategy: lockfile-only
|
@@ -0,0 +1,46 @@
|
|
1
|
+
name: Continuous Integration
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
- actions-*
|
8
|
+
tags:
|
9
|
+
- v*
|
10
|
+
pull_request:
|
11
|
+
branches-ignore:
|
12
|
+
- actions-*
|
13
|
+
workflow_dispatch:
|
14
|
+
|
15
|
+
env:
|
16
|
+
BUNDLE_CLEAN: "true"
|
17
|
+
BUNDLE_PATH: vendor/bundle
|
18
|
+
BUNDLE_JOBS: 3
|
19
|
+
BUNDLE_RETRY: 3
|
20
|
+
|
21
|
+
jobs:
|
22
|
+
build:
|
23
|
+
name: ${{ matrix.ruby }} build
|
24
|
+
runs-on: ubuntu-latest
|
25
|
+
strategy:
|
26
|
+
matrix:
|
27
|
+
include:
|
28
|
+
- ruby: "ruby"
|
29
|
+
standardrb: true
|
30
|
+
- ruby: "3.0"
|
31
|
+
- ruby: "2.7"
|
32
|
+
- ruby: "2.5"
|
33
|
+
steps:
|
34
|
+
- uses: actions/checkout@v2
|
35
|
+
- name: Set up Ruby
|
36
|
+
uses: ruby/setup-ruby@v1
|
37
|
+
with:
|
38
|
+
ruby-version: ${{ matrix.ruby}}
|
39
|
+
- name: Install gems
|
40
|
+
run: |
|
41
|
+
bundle install
|
42
|
+
- name: Run Tests
|
43
|
+
run: bundle exec rake
|
44
|
+
- name: standardrb
|
45
|
+
if: matrix.standardrb
|
46
|
+
run: bundle exec standardrb
|
data/.standard.yml
ADDED
data/CHANGE_LOG.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Changelog
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
|
+
|
7
|
+
## 1.0.0
|
8
|
+
|
9
|
+
### Added
|
10
|
+
|
11
|
+
- Initial release
|
data/MIT_LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2025 Brian Durand
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
# Lumberjack DataDog
|
2
|
+
|
3
|
+
[](https://github.com/bdurand/lumberjack_data_dog/actions/workflows/continuous_integration.yml)
|
4
|
+
[](https://github.com/testdouble/standard)
|
5
|
+
[](https://badge.fury.io/rb/lumberjack_data_dog)
|
6
|
+
|
7
|
+
This gem provides a logging setup for using the [lumberjack](https://github.com/bdurand/lumberjack) gem with DataDog. It sets up JSON logging and maps values to DataDog's [standard attributes](https://docs.datadoghq.com/logs/processing/attributes_naming_convention/).
|
8
|
+
|
9
|
+
## Features
|
10
|
+
|
11
|
+
- **DataDog Standard Attribute Mapping**: Automatically maps Lumberjack log fields to DataDog's standard attributes:
|
12
|
+
- `time` → `timestamp`
|
13
|
+
- `severity` → `status`
|
14
|
+
- `progname` → `logger.name`
|
15
|
+
- `pid` → `pid`
|
16
|
+
- **Exception Handling**: Structured exception logging with `kind`, `message`, and `stack` fields
|
17
|
+
- **Duration Logging**: Automatic conversion of duration values to nanoseconds for DataDog
|
18
|
+
- **Configurable Message Truncation**: Limit message length to prevent oversized logs
|
19
|
+
- **Thread Information**: Optional thread name logging
|
20
|
+
- **Tag Remapping**: Flexible tag transformation and remapping
|
21
|
+
- **Pretty JSON**: Optional pretty-printed JSON output for development
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
### Basic Setup
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
require 'lumberjack_data_dog'
|
29
|
+
|
30
|
+
# Create a logger that outputs to STDOUT
|
31
|
+
logger = Lumberjack::DataDog.setup
|
32
|
+
|
33
|
+
# Log messages
|
34
|
+
logger.info("Application started")
|
35
|
+
logger.warn("This is a warning", user_id: 123)
|
36
|
+
logger.error("Something went wrong", request_id: "abc-123")
|
37
|
+
```
|
38
|
+
|
39
|
+
### Advanced Configuration
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
logger = Lumberjack::DataDog.setup do |config|
|
43
|
+
# Truncate messages longer than 1000 characters
|
44
|
+
config.max_message_length = 1000
|
45
|
+
|
46
|
+
# Include thread information
|
47
|
+
config.thread_name = true # or :global for global thread ID
|
48
|
+
|
49
|
+
# Disable PID logging
|
50
|
+
config.pid = false
|
51
|
+
|
52
|
+
# Remap custom tags to DataDog attributes
|
53
|
+
config.remap_tags(
|
54
|
+
user_id: "usr.id",
|
55
|
+
request_id: "http.request_id"
|
56
|
+
)
|
57
|
+
|
58
|
+
# Enable pretty JSON for development
|
59
|
+
config.pretty = true
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
### Logging to a File
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
# Log to a file instead of STDOUT
|
67
|
+
File.open("/var/log/app.log", "a") do |file|
|
68
|
+
logger = Lumberjack::DataDog.setup(file)
|
69
|
+
logger.info("Logged to file")
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
### Exception Logging
|
74
|
+
|
75
|
+
Exceptions are automatically structured with DataDog's error attributes:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
begin
|
79
|
+
raise StandardError, "Something went wrong"
|
80
|
+
rescue => e
|
81
|
+
# Results in structured error with error.kind, error.message, and error.stack fields
|
82
|
+
logger.error(e)
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
### Duration Logging
|
87
|
+
|
88
|
+
Duration values are automatically converted to nanoseconds:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
# Log execution time
|
92
|
+
start_time = Time.now
|
93
|
+
# ... do some work ...
|
94
|
+
duration = Time.now - start_time
|
95
|
+
|
96
|
+
logger.info("Operation completed", duration: duration)
|
97
|
+
# duration is automatically converted to nanoseconds
|
98
|
+
|
99
|
+
# You can also use specific duration units
|
100
|
+
logger.info("DB query", duration_ms: 150.5) # milliseconds
|
101
|
+
logger.info("API call", duration_micros: 1500) # microseconds
|
102
|
+
logger.info("Function", duration_ns: 1500000) # nanoseconds
|
103
|
+
```
|
104
|
+
|
105
|
+
### Custom Tag Transformation
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
logger = Lumberjack::DataDog.setup do |config|
|
109
|
+
config.remap_tags(
|
110
|
+
# Simple remapping
|
111
|
+
correlation_id: "trace.correlation_id",
|
112
|
+
|
113
|
+
# Transform with a lambda
|
114
|
+
user_email: ->(email) { {"usr.email" => email.downcase} }
|
115
|
+
)
|
116
|
+
end
|
117
|
+
|
118
|
+
logger.info("User logged in", user_email: "USER@EXAMPLE.COM")
|
119
|
+
# Results in usr.email: "user@example.com"
|
120
|
+
```
|
121
|
+
|
122
|
+
## Installation
|
123
|
+
|
124
|
+
Add this line to your application's Gemfile:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
gem "lumberjack_data_dog"
|
128
|
+
```
|
129
|
+
|
130
|
+
And then execute:
|
131
|
+
```bash
|
132
|
+
$ bundle install
|
133
|
+
```
|
134
|
+
|
135
|
+
Or install it yourself as:
|
136
|
+
```bash
|
137
|
+
$ gem install lumberjack_data_dog
|
138
|
+
```
|
139
|
+
|
140
|
+
## Contributing
|
141
|
+
|
142
|
+
Open a pull request on GitHub.
|
143
|
+
|
144
|
+
Please use the [standardrb](https://github.com/testdouble/standard) syntax and lint your code with `standardrb --fix` before submitting.
|
145
|
+
|
146
|
+
## License
|
147
|
+
|
148
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "lumberjack_json_device"
|
4
|
+
|
5
|
+
module Lumberjack::DataDog
|
6
|
+
STANDARD_ATTRIBUTE_MAPPING = {
|
7
|
+
time: "timestamp",
|
8
|
+
severity: "status",
|
9
|
+
progname: ["logger", "name"],
|
10
|
+
pid: "pid"
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
class Config
|
14
|
+
attr_accessor :max_message_length
|
15
|
+
attr_accessor :backtrace_cleaner
|
16
|
+
attr_accessor :thread_name
|
17
|
+
attr_accessor :pid
|
18
|
+
attr_accessor :allow_all_tags
|
19
|
+
attr_reader :tag_mapping
|
20
|
+
attr_accessor :pretty
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@max_message_length = nil
|
24
|
+
@backtrace_cleaner = nil
|
25
|
+
@thread_name = false
|
26
|
+
@pid = true
|
27
|
+
@allow_all_tags = true
|
28
|
+
@tag_mapping = {}
|
29
|
+
@pretty = false
|
30
|
+
end
|
31
|
+
|
32
|
+
def remap_tags(tag_mapping)
|
33
|
+
@tag_mapping = @tag_mapping.merge(tag_mapping)
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate!
|
37
|
+
if !max_message_length.nil? && (!max_message_length.is_a?(Integer) || max_message_length <= 0)
|
38
|
+
raise ArgumentError, "max_message_length must be a positive integer"
|
39
|
+
end
|
40
|
+
|
41
|
+
unless backtrace_cleaner.nil? || backtrace_cleaner.respond_to?(:clean)
|
42
|
+
raise ArgumentError, "backtrace_cleaner must respond to #clean"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class << self
|
48
|
+
def setup(stream = $stdout, &block)
|
49
|
+
config = Config.new
|
50
|
+
yield(config) if block_given?
|
51
|
+
config.validate!
|
52
|
+
|
53
|
+
new_logger(stream, config)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def new_logger(stream, config)
|
59
|
+
logger = Lumberjack::Logger.new(json_device(stream, config))
|
60
|
+
|
61
|
+
# Add the error to the error tag if an exception is logged as the message.
|
62
|
+
logger.message_formatter.add(Exception, message_exception_formatter)
|
63
|
+
|
64
|
+
# Split the error tag up into standard attributes if it is an exception.
|
65
|
+
logger.tag_formatter.add(Exception, exception_tag_formatter(config))
|
66
|
+
|
67
|
+
if config.thread_name
|
68
|
+
if config.thread_name == :global
|
69
|
+
logger.tag_globally("logger.thread_name" => -> { Lumberjack::Utils.global_thread_id })
|
70
|
+
else
|
71
|
+
logger.tag_globally("logger.thread_name" => -> { Lumberjack::Utils.thread_name })
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
if config.pid == :global
|
76
|
+
logger.tag_globally("pid" => -> { Lumberjack::Utils.global_pid })
|
77
|
+
end
|
78
|
+
|
79
|
+
logger
|
80
|
+
end
|
81
|
+
|
82
|
+
def json_device(stream, config)
|
83
|
+
Lumberjack::JsonDevice.new(stream, mapping: json_mapping(config), pretty: config.pretty)
|
84
|
+
end
|
85
|
+
|
86
|
+
def json_mapping(config)
|
87
|
+
mapping = config.tag_mapping.transform_keys(&:to_sym)
|
88
|
+
mapping = mapping.merge(STANDARD_ATTRIBUTE_MAPPING)
|
89
|
+
|
90
|
+
mapping.delete(:pid) if !config.pid || config.pid == :global
|
91
|
+
|
92
|
+
mapping[:tags] = "*" if config.allow_all_tags
|
93
|
+
|
94
|
+
mapping[:message] = if config.max_message_length
|
95
|
+
truncate_message_transformer(config.max_message_length)
|
96
|
+
else
|
97
|
+
"message"
|
98
|
+
end
|
99
|
+
|
100
|
+
mapping[:duration] = duration_nanosecond_transformer(1_000_000_000)
|
101
|
+
mapping[:duration_ms] = duration_nanosecond_transformer(1_000_000)
|
102
|
+
mapping[:duration_micros] = duration_nanosecond_transformer(1_000)
|
103
|
+
mapping[:duration_ns] = duration_nanosecond_transformer(1)
|
104
|
+
|
105
|
+
mapping.transform_keys!(&:to_s)
|
106
|
+
end
|
107
|
+
|
108
|
+
def truncate_message_transformer(max_length)
|
109
|
+
lambda do |msg|
|
110
|
+
msg = msg.inspect unless msg.is_a?(String)
|
111
|
+
msg = msg[0, max_length] if msg.is_a?(String) && msg.length > max_length
|
112
|
+
{"message" => msg}
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def duration_nanosecond_transformer(multiplier)
|
117
|
+
lambda do |duration|
|
118
|
+
if duration.is_a?(Numeric)
|
119
|
+
{"duration" => (duration * multiplier).round}
|
120
|
+
else
|
121
|
+
{"duration" => nil}
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def message_exception_formatter
|
127
|
+
lambda do |error|
|
128
|
+
Lumberjack::Formatter::TaggedMessage.new(error.inspect, error: error)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def exception_tag_formatter(config)
|
133
|
+
lambda do |error|
|
134
|
+
error_tags = {"kind" => error.class.name, "message" => error.message}
|
135
|
+
trace = error.backtrace
|
136
|
+
if trace
|
137
|
+
trace = config.backtrace_cleaner.clean(trace) if config.backtrace_cleaner
|
138
|
+
error_tags["stack"] = trace
|
139
|
+
end
|
140
|
+
error_tags
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = "lumberjack_data_dog"
|
3
|
+
spec.version = File.read(File.join(__dir__, "VERSION")).strip
|
4
|
+
spec.authors = ["Brian Durand"]
|
5
|
+
spec.email = ["bbdurand@gmail.com"]
|
6
|
+
|
7
|
+
spec.summary = "Lumberjack logging device that outputs JSON formatted for DataDog with standard attribute mapping."
|
8
|
+
spec.homepage = "https://github.com/bdurand/lumberjack_data_dog"
|
9
|
+
spec.license = "MIT"
|
10
|
+
|
11
|
+
# Specify which files should be added to the gem when it is released.
|
12
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
13
|
+
ignore_files = %w[
|
14
|
+
.gitignore
|
15
|
+
.travis.yml
|
16
|
+
Appraisals
|
17
|
+
Gemfile
|
18
|
+
Gemfile.lock
|
19
|
+
Rakefile
|
20
|
+
gemfiles/
|
21
|
+
spec/
|
22
|
+
]
|
23
|
+
spec.files = Dir.chdir(__dir__) do
|
24
|
+
`git ls-files -z`.split("\x0").reject { |f| ignore_files.any? { |path| f.start_with?(path) } }
|
25
|
+
end
|
26
|
+
|
27
|
+
spec.require_paths = ["lib"]
|
28
|
+
|
29
|
+
spec.required_ruby_version = ">= 2.5"
|
30
|
+
|
31
|
+
spec.add_dependency "lumberjack_json_device", ">= 2.0.0"
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lumberjack_data_dog
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brian Durand
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-07-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: lumberjack_json_device
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.0.0
|
27
|
+
description:
|
28
|
+
email:
|
29
|
+
- bbdurand@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- ".github/dependabot.yml"
|
35
|
+
- ".github/workflows/continuous_integration.yml"
|
36
|
+
- ".standard.yml"
|
37
|
+
- CHANGE_LOG.md
|
38
|
+
- MIT_LICENSE.txt
|
39
|
+
- README.md
|
40
|
+
- VERSION
|
41
|
+
- lib/lumberjack/data_dog.rb
|
42
|
+
- lib/lumberjack_data_dog.rb
|
43
|
+
- lumberjack_data_dog.gemspec
|
44
|
+
homepage: https://github.com/bdurand/lumberjack_data_dog
|
45
|
+
licenses:
|
46
|
+
- MIT
|
47
|
+
metadata: {}
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '2.5'
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
requirements: []
|
63
|
+
rubygems_version: 3.4.10
|
64
|
+
signing_key:
|
65
|
+
specification_version: 4
|
66
|
+
summary: Lumberjack logging device that outputs JSON formatted for DataDog with standard
|
67
|
+
attribute mapping.
|
68
|
+
test_files: []
|