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.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/main.yml +33 -0
  3. data/.gitignore +24 -0
  4. data/.rspec +2 -0
  5. data/CHANGELOG.md +12 -0
  6. data/Gemfile +10 -0
  7. data/LICENSE.md +15 -0
  8. data/README.md +4 -0
  9. data/Rakefile +72 -0
  10. data/lib/logtail.rb +36 -0
  11. data/lib/logtail/config.rb +154 -0
  12. data/lib/logtail/config/integrations.rb +17 -0
  13. data/lib/logtail/context.rb +9 -0
  14. data/lib/logtail/contexts.rb +12 -0
  15. data/lib/logtail/contexts/http.rb +31 -0
  16. data/lib/logtail/contexts/release.rb +52 -0
  17. data/lib/logtail/contexts/runtime.rb +23 -0
  18. data/lib/logtail/contexts/session.rb +24 -0
  19. data/lib/logtail/contexts/system.rb +29 -0
  20. data/lib/logtail/contexts/user.rb +28 -0
  21. data/lib/logtail/current_context.rb +168 -0
  22. data/lib/logtail/event.rb +36 -0
  23. data/lib/logtail/events.rb +10 -0
  24. data/lib/logtail/events/controller_call.rb +44 -0
  25. data/lib/logtail/events/error.rb +40 -0
  26. data/lib/logtail/events/exception.rb +10 -0
  27. data/lib/logtail/events/sql_query.rb +26 -0
  28. data/lib/logtail/events/template_render.rb +25 -0
  29. data/lib/logtail/integration.rb +40 -0
  30. data/lib/logtail/integrator.rb +50 -0
  31. data/lib/logtail/log_devices.rb +8 -0
  32. data/lib/logtail/log_devices/http.rb +368 -0
  33. data/lib/logtail/log_devices/http/flushable_dropping_sized_queue.rb +52 -0
  34. data/lib/logtail/log_devices/http/request_attempt.rb +20 -0
  35. data/lib/logtail/log_entry.rb +110 -0
  36. data/lib/logtail/logger.rb +270 -0
  37. data/lib/logtail/logtail.rb +36 -0
  38. data/lib/logtail/timer.rb +21 -0
  39. data/lib/logtail/util.rb +7 -0
  40. data/lib/logtail/util/non_nil_hash_builder.rb +40 -0
  41. data/lib/logtail/version.rb +3 -0
  42. data/logtail-ruby.gemspec +43 -0
  43. data/spec/README.md +13 -0
  44. data/spec/logtail/current_context_spec.rb +113 -0
  45. data/spec/logtail/events/controller_call_spec.rb +12 -0
  46. data/spec/logtail/events/error_spec.rb +15 -0
  47. data/spec/logtail/log_devices/http_spec.rb +185 -0
  48. data/spec/logtail/log_entry_spec.rb +22 -0
  49. data/spec/logtail/logger_spec.rb +227 -0
  50. data/spec/spec_helper.rb +22 -0
  51. data/spec/support/logtail.rb +5 -0
  52. data/spec/support/socket_hostname.rb +12 -0
  53. data/spec/support/timecop.rb +3 -0
  54. data/spec/support/webmock.rb +3 -0
  55. 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
@@ -0,0 +1,2 @@
1
+ --color
2
+ --order rand
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
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in logtail-ruby.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rspec", "~> 3.0"
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,9 @@
1
+ module Logtail
2
+ # Base class for all `Logtail::Contexts::*` classes.
3
+ # @private
4
+ class Context
5
+ def to_hash
6
+ raise(NotImplementedError.new)
7
+ end
8
+ end
9
+ 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