logtail-ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![ISC License](https://img.shields.io/badge/license-ISC-ff69b4.svg)](LICENSE.md)
|
4
|
+
[![Build Status](https://github.com/logtail/logtail-ruby/workflows/build/badge.svg)](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
|