logtail-ruby 0.1.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/workflows/main.yml +33 -0
- data/.gitignore +24 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +10 -0
- data/LICENSE.md +15 -0
- data/README.md +4 -0
- data/Rakefile +72 -0
- data/lib/logtail.rb +36 -0
- data/lib/logtail/config.rb +154 -0
- data/lib/logtail/config/integrations.rb +17 -0
- data/lib/logtail/context.rb +9 -0
- data/lib/logtail/contexts.rb +12 -0
- data/lib/logtail/contexts/http.rb +31 -0
- data/lib/logtail/contexts/release.rb +52 -0
- data/lib/logtail/contexts/runtime.rb +23 -0
- data/lib/logtail/contexts/session.rb +24 -0
- data/lib/logtail/contexts/system.rb +29 -0
- data/lib/logtail/contexts/user.rb +28 -0
- data/lib/logtail/current_context.rb +168 -0
- data/lib/logtail/event.rb +36 -0
- data/lib/logtail/events.rb +10 -0
- data/lib/logtail/events/controller_call.rb +44 -0
- data/lib/logtail/events/error.rb +40 -0
- data/lib/logtail/events/exception.rb +10 -0
- data/lib/logtail/events/sql_query.rb +26 -0
- data/lib/logtail/events/template_render.rb +25 -0
- data/lib/logtail/integration.rb +40 -0
- data/lib/logtail/integrator.rb +50 -0
- data/lib/logtail/log_devices.rb +8 -0
- data/lib/logtail/log_devices/http.rb +368 -0
- data/lib/logtail/log_devices/http/flushable_dropping_sized_queue.rb +52 -0
- data/lib/logtail/log_devices/http/request_attempt.rb +20 -0
- data/lib/logtail/log_entry.rb +110 -0
- data/lib/logtail/logger.rb +270 -0
- data/lib/logtail/logtail.rb +36 -0
- data/lib/logtail/timer.rb +21 -0
- data/lib/logtail/util.rb +7 -0
- data/lib/logtail/util/non_nil_hash_builder.rb +40 -0
- data/lib/logtail/version.rb +3 -0
- data/logtail-ruby.gemspec +43 -0
- data/spec/README.md +13 -0
- data/spec/logtail/current_context_spec.rb +113 -0
- data/spec/logtail/events/controller_call_spec.rb +12 -0
- data/spec/logtail/events/error_spec.rb +15 -0
- data/spec/logtail/log_devices/http_spec.rb +185 -0
- data/spec/logtail/log_entry_spec.rb +22 -0
- data/spec/logtail/logger_spec.rb +227 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/logtail.rb +5 -0
- data/spec/support/socket_hostname.rb +12 -0
- data/spec/support/timecop.rb +3 -0
- data/spec/support/webmock.rb +3 -0
- metadata +238 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5523213c7b76d65ee65d2cb78a7ae670bf08befe691a39d0e21314a213342026
|
4
|
+
data.tar.gz: 3a2ec12ce069f3dfb65486a77547ca8e2c43be313a4493067ea3f8df2d502db6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d6ff799030c337cf62811e4a29ecee47e3141f4c7870e9686fdb7f38b071ad758b4dcea6f05b5df44b78dd3fea4fd1c82643466e9a21e2fc445908b4e34e6259
|
7
|
+
data.tar.gz: 51157471d26432a6287f7ec4c3b3832609aa133fb36fa21939c8bd8a2b7f8ecd5d34100159fbbc9a129e32eb2cb8def110e11d9b938acd67ee450ee81a2ee512
|
@@ -0,0 +1,33 @@
|
|
1
|
+
name: build
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
|
8
|
+
runs-on: ubuntu-20.04
|
9
|
+
|
10
|
+
strategy:
|
11
|
+
matrix:
|
12
|
+
ruby-version:
|
13
|
+
- 3.0.0
|
14
|
+
- 2.7.2
|
15
|
+
- 2.6.6
|
16
|
+
- 2.5.8
|
17
|
+
- 2.4.10
|
18
|
+
- 2.3.8
|
19
|
+
- 2.2.10
|
20
|
+
- jruby-9.2.14.0
|
21
|
+
- truffleruby-21.0.0
|
22
|
+
|
23
|
+
steps:
|
24
|
+
- uses: actions/checkout@v2
|
25
|
+
|
26
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
27
|
+
uses: ruby/setup-ruby@v1
|
28
|
+
with:
|
29
|
+
ruby-version: ${{ matrix.ruby-version }}
|
30
|
+
bundler-cache: true
|
31
|
+
|
32
|
+
- name: Run tests
|
33
|
+
run: bundle exec rspec --format documentation
|
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
/doc/
|
2
|
+
/pkg/
|
3
|
+
/spec/reports/
|
4
|
+
/tmp/
|
5
|
+
|
6
|
+
# rspec failure tracking
|
7
|
+
.rspec_status
|
8
|
+
.DS_Store
|
9
|
+
.rvmrc
|
10
|
+
.ruby-version
|
11
|
+
coverage
|
12
|
+
Gemfile.lock
|
13
|
+
*.swp
|
14
|
+
*.gem
|
15
|
+
|
16
|
+
Gemfile.lock
|
17
|
+
gemfiles/*.lock
|
18
|
+
|
19
|
+
/.bundle
|
20
|
+
/.yardoc
|
21
|
+
/doc
|
22
|
+
/log
|
23
|
+
/tmp
|
24
|
+
/pkg
|
data/.rspec
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
6
|
+
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [Unreleased]
|
9
|
+
|
10
|
+
## [1.0.0] - 2021-02-11
|
11
|
+
|
12
|
+
- The first version of the client.
|
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# License
|
2
|
+
|
3
|
+
Copyright (c) 2016, Logtail
|
4
|
+
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
6
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
7
|
+
and this permission notice appear in all copies.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
11
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
13
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
14
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
15
|
+
THIS SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,4 @@
|
|
1
|
+
# 🪵 Logtail - Ruby Logging For Everyone
|
2
|
+
|
3
|
+
[](LICENSE.md)
|
4
|
+
[](https://github.com/logtail/logtail-ruby/actions?query=workflow%3Abuild)
|
data/Rakefile
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "logtail"
|
3
|
+
|
4
|
+
def puts_with_level(message, level = :info)
|
5
|
+
case level
|
6
|
+
when :info
|
7
|
+
puts("\e[31m#{message}\e[0m")
|
8
|
+
when :error
|
9
|
+
puts("\e[31m#{message}\e[0m")
|
10
|
+
when :success
|
11
|
+
puts("\e[32m#{message}\e[0m")
|
12
|
+
else
|
13
|
+
puts(message)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
task :test_the_pipes, [:api_key] do |t, args|
|
18
|
+
support_email = "support@logtail.com"
|
19
|
+
# Do not modify below this line. It's important to keep the `Logtail::Logger`
|
20
|
+
# because it provides an API for logging structured data and capturing context.
|
21
|
+
header = <<~HEREDOC
|
22
|
+
### I want our own pixelart too, but no time for that for now ###
|
23
|
+
HEREDOC
|
24
|
+
|
25
|
+
puts header
|
26
|
+
|
27
|
+
current_context = Logtail::CurrentContext.instance.snapshot
|
28
|
+
entry = Logtail::LogEntry.new(:info, Time.now, nil, "Testing the pipes (click the inspect icon to view more details)", current_context, nil)
|
29
|
+
http_device = Logtail::LogDevices::HTTP.new(args.api_key, flush_continuously: false)
|
30
|
+
response = http_device.deliver_one(entry)
|
31
|
+
if response.is_a?(Exception)
|
32
|
+
message = <<~HEREDOC
|
33
|
+
Unable to deliver logs.
|
34
|
+
Here's what we received from the Logtail API:
|
35
|
+
#{response.inspect}
|
36
|
+
If you continue to have trouble please contact support:
|
37
|
+
#{support_email}
|
38
|
+
HEREDOC
|
39
|
+
puts_with_level(message, :error)
|
40
|
+
elsif response.is_a?(Net::HTTPResponse)
|
41
|
+
if response.code.start_with? '2'
|
42
|
+
puts_with_level("Logs successfully sent! View them at https://logtail.com",
|
43
|
+
:success)
|
44
|
+
else
|
45
|
+
message =
|
46
|
+
<<~HEREDOC
|
47
|
+
Unable to deliver logs.
|
48
|
+
We received a #{response.code} response from the Logtail API:
|
49
|
+
#{response.body.inspect}
|
50
|
+
If you continue to have trouble please contact support:
|
51
|
+
#{support_email}
|
52
|
+
HEREDOC
|
53
|
+
puts_with_level(message, :error)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
task :console do
|
59
|
+
require 'irb'
|
60
|
+
require 'irb/completion'
|
61
|
+
require 'logtail'
|
62
|
+
$VERBOSE = nil
|
63
|
+
|
64
|
+
def reload!
|
65
|
+
files = $LOADED_FEATURES.select { |feat| feat =~ /\/logtail\// }
|
66
|
+
files.each { |file| load file }
|
67
|
+
"reloaded"
|
68
|
+
end
|
69
|
+
|
70
|
+
ARGV.clear
|
71
|
+
IRB.start
|
72
|
+
end
|
data/lib/logtail.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Base (must come first, order matters)
|
2
|
+
require "logtail/version"
|
3
|
+
require "logtail/config"
|
4
|
+
require "logtail/util"
|
5
|
+
|
6
|
+
# Load frameworks
|
7
|
+
|
8
|
+
# Other (sorted alphabetically)
|
9
|
+
require "logtail/contexts"
|
10
|
+
require "logtail/current_context"
|
11
|
+
require "logtail/events"
|
12
|
+
require "logtail/integration"
|
13
|
+
require "logtail/log_devices"
|
14
|
+
require "logtail/log_entry"
|
15
|
+
require "logtail/logger"
|
16
|
+
require "logtail/timer"
|
17
|
+
require "logtail/integrator"
|
18
|
+
require "logtail/integration"
|
19
|
+
|
20
|
+
module Logtail
|
21
|
+
# Access the main configuration object. Please see {{Logtail::Config}} for more details.
|
22
|
+
def self.config
|
23
|
+
Config.instance
|
24
|
+
end
|
25
|
+
|
26
|
+
# Starts a timer for timing events. Please see {{Logtail::Logtail.start}} for more details.
|
27
|
+
def self.start_timer
|
28
|
+
Timer.start
|
29
|
+
end
|
30
|
+
|
31
|
+
# Adds context to all logs written within the passed block. Please see
|
32
|
+
# {{Logtail::CurrentContext.with}} for a more detailed description with examples.
|
33
|
+
def self.with_context(context, &block)
|
34
|
+
CurrentContext.with(context, &block)
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require "logger"
|
2
|
+
require "singleton"
|
3
|
+
|
4
|
+
module Logtail
|
5
|
+
# Singleton class for reading and setting Logtail configuration.
|
6
|
+
#
|
7
|
+
# For Rails apps, this is installed into `config.logtail`. See examples below.
|
8
|
+
#
|
9
|
+
# @example Rails example
|
10
|
+
# config.logtail.append_metadata = false
|
11
|
+
# @example Everything else
|
12
|
+
# config = Logtail::Config.instance
|
13
|
+
# config.append_metdata = false
|
14
|
+
class Config
|
15
|
+
# @private
|
16
|
+
class NoLoggerError < StandardError; end
|
17
|
+
|
18
|
+
# @private
|
19
|
+
class SimpleLogFormatter < ::Logger::Formatter
|
20
|
+
# This method is invoked when a log event occurs
|
21
|
+
def call(severity, timestamp, progname, msg)
|
22
|
+
"[Logtail] #{String === msg ? msg : msg.inspect}\n"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
DEVELOPMENT_NAME = "development".freeze
|
27
|
+
PRODUCTION_NAME = "production".freeze
|
28
|
+
STAGING_NAME = "staging".freeze
|
29
|
+
TEST_NAME = "test".freeze
|
30
|
+
|
31
|
+
include Singleton
|
32
|
+
|
33
|
+
attr_writer :http_body_limit
|
34
|
+
|
35
|
+
# Convenience method for logging debug statements to the debug logger
|
36
|
+
# set in this class.
|
37
|
+
# @private
|
38
|
+
def debug(&block)
|
39
|
+
debug_logger = Config.instance.debug_logger
|
40
|
+
if debug_logger
|
41
|
+
message = yield
|
42
|
+
debug_logger.debug(message)
|
43
|
+
end
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
# This is useful for debugging. This Sets a debug_logger to view internal Logtail library
|
48
|
+
# log messages. The default is `nil`. Meaning log to nothing.
|
49
|
+
#
|
50
|
+
# See {#debug_to_file!} and {#debug_to_stdout!} for convenience methods that handle creating
|
51
|
+
# and setting the logger.
|
52
|
+
#
|
53
|
+
# @example Rails
|
54
|
+
# config.logtail.debug_logger = ::Logger.new(STDOUT)
|
55
|
+
# @example Everything else
|
56
|
+
# Logtail::Config.instance.debug_logger = ::Logger.new(STDOUT)
|
57
|
+
def debug_logger=(value)
|
58
|
+
@debug_logger = value
|
59
|
+
end
|
60
|
+
|
61
|
+
# Accessor method for {#debug_logger=}.
|
62
|
+
def debug_logger
|
63
|
+
@debug_logger
|
64
|
+
end
|
65
|
+
|
66
|
+
# A convenience method for writing internal Logtail debug messages to a file.
|
67
|
+
#
|
68
|
+
# @example Rails
|
69
|
+
# config.Logtail.debug_to_file!("#{Rails.root}/log/logtail.log")
|
70
|
+
# @example Everything else
|
71
|
+
# Logtail::Config.instance.debug_to_file!("log/logtail.log")
|
72
|
+
def debug_to_file!(file_path)
|
73
|
+
FileUtils.mkdir_p( File.dirname(file_path) )
|
74
|
+
file = File.open(file_path, "ab")
|
75
|
+
file_logger = ::Logger.new(file)
|
76
|
+
file_logger.formatter = SimpleLogFormatter.new
|
77
|
+
self.debug_logger = file_logger
|
78
|
+
end
|
79
|
+
|
80
|
+
# A convenience method for writing internal Logtail debug messages to STDOUT.
|
81
|
+
#
|
82
|
+
# @example Rails
|
83
|
+
# config.logtail.debug_to_stdout!
|
84
|
+
# @example Everything else
|
85
|
+
# Logtail::Config.instance.debug_to_stdout!
|
86
|
+
def debug_to_stdout!
|
87
|
+
stdout_logger = ::Logger.new(STDOUT)
|
88
|
+
stdout_logger.formatter = SimpleLogFormatter.new
|
89
|
+
self.debug_logger = stdout_logger
|
90
|
+
end
|
91
|
+
|
92
|
+
# The environment your app is running in. Defaults to `RACK_ENV` and `RAILS_ENV`.
|
93
|
+
# It should be rare that you have to set this. If the aforementioned env vars are not
|
94
|
+
# set please do.
|
95
|
+
#
|
96
|
+
# @example If you do not set `RACK_ENV` or `RAILS_ENV`
|
97
|
+
# Logtail::Config.instance.environment = "staging"
|
98
|
+
def environment=(value)
|
99
|
+
@environment = value
|
100
|
+
end
|
101
|
+
|
102
|
+
# Accessor method for {#environment=}
|
103
|
+
def environment
|
104
|
+
@environment ||= ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "development"
|
105
|
+
end
|
106
|
+
|
107
|
+
# Convenience method for accessing the various `Logtail::Integrations::*` class
|
108
|
+
# settings. These provides settings for enabling, disabled, and silencing integrations.
|
109
|
+
# See {Integrations} for a full list of available methods.
|
110
|
+
def integrations
|
111
|
+
Integrations
|
112
|
+
end
|
113
|
+
|
114
|
+
# This is the _main_ logger Logtail writes to. All of the Logtail integrations write to
|
115
|
+
# this logger instance. It should be set to your global logger. For Rails, this is set
|
116
|
+
# automatically to `Rails.logger`, you should not have to set this.
|
117
|
+
#
|
118
|
+
# @example Non-rails frameworks
|
119
|
+
# my_global_logger = Logtail::Logger.new(STDOUT)
|
120
|
+
# Logtail::Config.instance.logger = my_global_logger
|
121
|
+
def logger=(value)
|
122
|
+
@logger = value
|
123
|
+
end
|
124
|
+
|
125
|
+
# Accessor method for {#logger=}.
|
126
|
+
def logger
|
127
|
+
if @logger.is_a?(Proc)
|
128
|
+
@logger.call()
|
129
|
+
else
|
130
|
+
@logger ||= Logger.new(STDOUT)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# @private
|
135
|
+
def development?
|
136
|
+
environment == DEVELOPMENT_NAME
|
137
|
+
end
|
138
|
+
|
139
|
+
# @private
|
140
|
+
def test?
|
141
|
+
environment == TEST_NAME
|
142
|
+
end
|
143
|
+
|
144
|
+
# @private
|
145
|
+
def production?
|
146
|
+
environment == PRODUCTION_NAME
|
147
|
+
end
|
148
|
+
|
149
|
+
# @private
|
150
|
+
def staging?
|
151
|
+
environment == STAGING_NAME
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Logtail
|
2
|
+
class Config
|
3
|
+
# Convenience module for accessing the various `Logtail::Integrations::*` classes
|
4
|
+
# through the {Logtail::Config} object. Logtail couples configuration with the class
|
5
|
+
# responsible for implementing it. This provides for a tighter design, but also
|
6
|
+
# requires the user to understand and access the various classes. This module aims
|
7
|
+
# to provide a simple ruby-like configuration interface for internal Logtail classes.
|
8
|
+
#
|
9
|
+
# For example:
|
10
|
+
#
|
11
|
+
# config = Logtail::Config.instance
|
12
|
+
# config.integrations.active_record.silence = true
|
13
|
+
module Integrations
|
14
|
+
extend self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "logtail/contexts/http"
|
2
|
+
require "logtail/contexts/release"
|
3
|
+
require "logtail/contexts/runtime"
|
4
|
+
require "logtail/contexts/session"
|
5
|
+
require "logtail/contexts/system"
|
6
|
+
require "logtail/contexts/user"
|
7
|
+
|
8
|
+
module Logtail
|
9
|
+
# @private
|
10
|
+
module Contexts
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "logtail/context"
|
2
|
+
|
3
|
+
module Logtail
|
4
|
+
module Contexts
|
5
|
+
# @private
|
6
|
+
class HTTP < Context
|
7
|
+
attr_reader :host, :method, :path, :remote_addr, :request_id
|
8
|
+
|
9
|
+
def initialize(attributes)
|
10
|
+
@host = attributes[:host]
|
11
|
+
@method = attributes[:method]
|
12
|
+
@path = attributes[:path]
|
13
|
+
@remote_addr = attributes[:remote_addr]
|
14
|
+
@request_id = attributes[:request_id]
|
15
|
+
end
|
16
|
+
|
17
|
+
# Builds a hash representation containing simple objects, suitable for serialization (JSON).
|
18
|
+
def to_hash
|
19
|
+
@to_hash ||= {
|
20
|
+
http: Util::NonNilHashBuilder.build do |h|
|
21
|
+
h.add(:host, host)
|
22
|
+
h.add(:method, method)
|
23
|
+
h.add(:path, path)
|
24
|
+
h.add(:remote_addr, remote_addr)
|
25
|
+
h.add(:request_id, request_id)
|
26
|
+
end
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|