Giter Club home page Giter Club logo

ruby's Introduction

Ruby gem for logging to LogDNA


All Contributors

Installation

Add this line to your application's Gemfile:

gem 'logdna'

And then execute:

$ bundle

Or install it yourself as:

$ gem install logdna

Quick Setup

After installation, call

logger = Logdna::Ruby.new(your_api_key, options)
#<Logdna::Ruby:0x00000000000000>

to set up the logger.

Options are optional variables that may contain hostname, app name, mac address, ip address, log level specified.

options = {
    :hostname => myHostName,
    :ip =>  myIpAddress,
    :mac => myMacAddress,
    :app => myAppName,
    :level => "INFO",    # LOG_LEVELS = ['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'] or your customized log level (custom levels for Rails have to be sent with a log message)
    :env => "PRODUCTION",
    :meta => {:once => {:first => "nested1", :another => "nested2"}},
    :endpoint => "https://fqdn/logs/ingest"
}

To send logs, use "log" method. Default log level is "INFO"

logger.log('This is my first log')
=> "Saved"  # Saved to buffer. Ready to be flushed automatically

Optionally you can use a block to do so

logger.log { 'This is my second log' }
=> "Saved"

Log a message with particular metadata, level, appname, environment (one-time)

logger.log('This is warn message', {:meta => {:meta => "data"}, :level => "WARN", :app => "awesome", :env => "DEVELOPMENT"})

Log a message with lasting metadata, level, appname, environment (lasting)

logger.meta = {:once => {:first => "nested1", :another => "nested2"}}
logger.level = 'FATAL'  or  logger.level = Logger::FATAL
logger.app = 'NEW APP NAME'
logger.env = 'PRODUCTION'
logger.log('This messages and messages afterwards all have the above values')

Clear current metadata, level, appname, environment

logger.clear

Check current log level: logger.info? => true logger.warn? => false

Log a message with a particular level easily

logger.warn('This is a warning message')
logger.fatal('This is a fatal message')
logger.debug { 'This is a debug message' }

Hostname and app name cannot be more than 80 characters.

Rails Setup

In your config/environments/environment.rb:

Rails.application.configure do
  config.logger = Logdna::Ruby.new(your_api_key, options)
end

Important Notes

  1. This logger assumes that you pass in json formatted data
  2. This logger is a singleton (do not create mutiple instances of the logger) even though the singleton structure is not strongly enforced.

API

Logdna::Ruby.new(ingestion_key, options = {})

Instantiates a new instance of the class it is called on. ingestion_key is required.

Options Default
{ :hostname => Host name } Device's default hostname
{ :mac => MAC address } Nil
{ :ip => IP address } Nil
{ :app => App name } 'default'
{ :level => Log level } 'INFO'
{ :env => STAGING, PRODUCTION .. etc} Nil
{ :meta => metadata} Nil
{ :endpoint => LogDNA Ingestion URI 'https://logs.logdna.com/logs/ingest'
{ :flush_interval => Limit to trigger a flush in seconds } 0.25 seconds
{ :flush_size => Limit to trigger a flush in bytes } 2097152 bytes = 2 MiB
{ :request_size => Upper limit of request in bytes } 2097152 bytes = 2 MiB
{ :retry_timeout => Base timeout for retries in seconds } 0.25 seconds
{ :retry_max_attempts => Maximum number of retries per request } 3 attempts
{ :retry_max_jitter => Maximum amount of jitter to add to each retry request in seconds } 0.25 seconds

Different log level displays log messages in different colors as well.

  • TRACE DEBUG INFO Colors "Trace" "Debug" "Info"
  • WARN Color "Warn"
  • ERROR Fatal Colors "Error" "Fatal"

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/logdna/ruby.

Contributors ✨

Thanks goes to these wonderful people (emoji key):


Amadeus Folego

πŸ›

Brad

πŸ’» πŸ“–

DChai

πŸ‘€ πŸ’»

Dee Evans

πŸ›

Greg Swift

πŸ’»

Gun Woo choi

πŸ’» πŸ“–

Jacob Hull

πŸ’»

Jon Moses

⚠️

Kenneth-KT

πŸ’»

Mansoor

πŸ›

Mike Machado

πŸ›

Muaz Siddiqui

πŸ’» 🚧 πŸ‘€

Oleg Kiviljov

πŸ›

Peter JΓΆnsson

πŸš‡

Phil Ciampini

πŸ’» ⚠️

Samir Musali

πŸ’» πŸ“– 🚧

vilyapilya

πŸ’» πŸ“–

This project follows the all-contributors specification. Contributions of any kind welcome!

License

The gem is available as open source under the terms of the MIT License.

ruby's People

Contributors

bnauta avatar dchai76 avatar esatterwhite avatar gregswift avatar jakedipity avatar jmoses avatar kenneth-kt avatar mattchoi1 avatar mindjiver avatar respectus avatar smusali avatar vilyapilya avatar yiziz avatar zeldanut avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ruby's Issues

Incompatible with Rails 7.1 ? (conflating `log_level` and `level`)

I recently tried upgrading to Rails 7.1, but this gem seems to be causing an error:

ArgumentError: comparison of String with 0 failed

The issue does not occur after removing the logdna gem from my app.

I believe the issue is caused by Rails.logger.level returning a string (e.g. INFO) whereas Rails expects it to be an integer. See the Rails docs here: https://guides.rubyonrails.org/v7.1/debugging_rails_applications.html#log-levels

The available log levels are: :debug, :info, :warn, :error, :fatal, and :unknown, corresponding to the log level numbers from 0 up to 5, respectively. […]

It seems like the logdna gem is conflating log_level and level:

ruby/lib/logdna.rb

Lines 57 to 68 in 9d33a2f

def level
@log_level
end
def level=(value)
if value.is_a? Numeric
@log_level = Resources::LOG_LEVELS[value]
return
end
@log_level = value
end

Full stack trace:

Oct 13 04:25:16 PM  rake aborted!
Oct 13 04:25:16 PM  ArgumentError: comparison of String with 0 failed
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activesupport-7.1.1/lib/active_support/log_subscriber.rb:140:in `>'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activesupport-7.1.1/lib/active_support/log_subscriber.rb:140:in `silenced?'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activesupport-7.1.1/lib/active_support/notifications/fanout.rb:203:in `block (2 levels) in groups_for'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activesupport-7.1.1/lib/active_support/notifications/fanout.rb:203:in `reject'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activesupport-7.1.1/lib/active_support/notifications/fanout.rb:203:in `block in groups_for'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activesupport-7.1.1/lib/active_support/notifications/fanout.rb:202:in `each'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activesupport-7.1.1/lib/active_support/notifications/fanout.rb:202:in `groups_for'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activesupport-7.1.1/lib/active_support/notifications/fanout.rb:232:in `initialize'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activesupport-7.1.1/lib/active_support/notifications/fanout.rb:271:in `new'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activesupport-7.1.1/lib/active_support/notifications/fanout.rb:271:in `build_handle'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activesupport-7.1.1/lib/active_support/notifications/instrumenter.rb:79:in `build_handle'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activesupport-7.1.1/lib/active_support/notifications/instrumenter.rb:55:in `instrument'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract_adapter.rb:1134:in `log'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:51:in `raw_execute'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:519:in `internal_execute'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/postgresql/schema_statements.rb:245:in `client_min_messages='
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/postgresql_adapter.rb:1002:in `configure_connection'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract_adapter.rb:693:in `block (2 levels) in reconnect!'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:374:in `reset_transaction'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract_adapter.rb:691:in `block in reconnect!'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activesupport-7.1.1/lib/active_support/concurrency/null_lock.rb:9:in `synchronize'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract_adapter.rb:684:in `reconnect!'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract_adapter.rb:788:in `verify!'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract_adapter.rb:795:in `connect!'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract_adapter.rb:997:in `block in with_raw_connection'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activesupport-7.1.1/lib/active_support/concurrency/null_lock.rb:9:in `synchronize'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract_adapter.rb:996:in `with_raw_connection'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract_adapter.rb:1104:in `valid_raw_connection'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/postgresql_adapter.rb:619:in `get_database_version'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/schema_cache.rb:374:in `database_version'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/schema_cache.rb:70:in `database_version'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/schema_cache.rb:200:in `database_version'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract_adapter.rb:871:in `database_version'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/postgresql_adapter.rb:647:in `check_version'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:675:in `new_connection'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:720:in `checkout_new_connection'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:699:in `try_to_checkout_new_connection'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:657:in `acquire_connection'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:355:in `checkout'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:184:in `connection'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_adapters/abstract/connection_handler.rb:246:in `retrieve_connection'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_handling.rb:287:in `retrieve_connection'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/connection_handling.rb:254:in `connection'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/tasks/database_tasks.rb:510:in `migration_connection'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/tasks/database_tasks.rb:243:in `migrate'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/strong_migrations-1.6.3/lib/strong_migrations/database_tasks.rb:5:in `migrate'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/activerecord-7.1.1/lib/active_record/railties/databases.rake:93:in `block (2 levels) in <main>'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/bugsnag-6.26.0/lib/bugsnag/integrations/rake.rb:20:in `execute'
Oct 13 04:25:16 PM  /opt/render/project/.gems/ruby/3.2.0/gems/rake-13.0.6/exe/rake:27:in `<top (required)>'
Oct 13 04:25:16 PM  /opt/render/project/.gems/bin/bundle:113:in `load'
Oct 13 04:25:16 PM  /opt/render/project/.gems/bin/bundle:113:in `<main>'
Oct 13 04:25:16 PM  Tasks: TOP => db:migrate
Oct 13 04:25:16 PM  (See full trace by running task with --trace)
Oct 13 04:25:16 PM  ==> Build failed 😞

Logs are not sent to LogDNA

Hello, I've setup the logger for the rails based on the code I've found in gem (not readme)

config.logger = LogDNA::RubyLogger.new(myapikey, myhostname, opts)

but it does not send any logs to LogDNA, what can be the issue here?

Calls to `#log` with progname are swallowed and only progname is sent to LogDNA

According to the Ruby docs for the Logger class, #log has a call pattern where a progname is provided and a block is executed only if the log level is high enough to actually log the message.

This call pattern is not supported by this library, and it in fact breaks log messages sent using this method by treating progname as the message and throwing away the message.

If you're using Sentry and wondering why your logs are full of messages that consist solely of "sentry", this is the cause.

Include Rails log_tags in metadata

I've made this change locally. But I think it could go in the public gem. I'm using ActiveSupport::TaggedLogging in Rails to include log tags like this:

# This is the default in Rails, but could include more stuff if desired
config.log_tags = [:request_id]

# Send logs to LogDNA
log_dna_logger = Logdna::Ruby.new(
  Rails.application.secrets.log_dna_api_key, {
    env: "development",
    app: "ShayHi",
    level: Logger::DEBUG
  }
)
# Wrap LogDNA logger in TaggedLogging to add log tags
config.logger = ActiveSupport::TaggedLogging.new(log_dna_logger)

I then modified Logdna::Ruby#log to include the tags in the metadata

def log(message = nil, opts = {})
  # MY NEW CODE BELOW vvv
  if formatter.current_tags.present?
    opts[:meta] = (opts[:meta] || {}).merge(tags: formatter.current_tags.join(" "))
  end
  # MY NEW CODE ABOVE ^^^
  if message.nil? && block_given?
    message = yield
  end
  if message.nil?
    @internal_logger.debug("provide either a message or block")
    return
  end
  message = message.to_s.encode("UTF-8")
  @client.write_to_buffer(message, default_opts.merge(opts).merge(
                                     timestamp: (Time.now.to_f * 1000).to_i
                                   ))
end

Logs now look like this:

tags

This is particularly useful for including the Rails request_id in the log metadata. I can open a PR if this is something you're interested in adding to the gem for everyone.

Agent sending logs during requests

After including logdna to our application we are seeing increased response times, the agent is sending logs during the request lifecycle (taking up to 40% of the response time).

Given the rails gem is deprecated as per-notice, how does one configure this gem to avoid such an issue?

uninitialized constant Logdna

Hello, why the readme suggests to setup the logger by using:

Logdna::Ruby

while quick browsing of the library code shows that the actual namespace and logger class are:

LogDNA::RubyLogger

Logs failing to flush in `Logdna::Client` due to concurrency issue in rails

Found that any uses of Logdna::Client within the boot sequence of rails results in subsequent logs never flushing.

For background, using logdna 1.5.0 w/ rails 6.1.7.5 on ruby 3.2.2. Configuring Logdna::Ruby following the instructions in TAMING RUBY ON RAILS LOGGING WITH LOGRAGE AND MEZMO in config/application.rb. As long as Rails.logger isn't used within the subsequent application setup steps, then logging works as expected. But if any other subsequent step of the application setup process attempts to log, then all subsequent logs fail to be emitted.

Tracked this down to Logdna::Client#schedule_flush. By adding logging, I found that the associated Concurrent::ScheduledTask in @scheduled_flush remains in the pending state indefinitely. Further logging shows that the ScheduledTask is associated with a Concurrent::CachedThreadPool that contains a single thread and that thread has is marked as dead.

Guessing that as part of the rails boot up process, the default executor is terminated and therefore the @scheduled_flush never completes. Not that using the @work_thread_pool thread pool doesn't fix the issue; the same behavior is observed. By not logging anything during rails configurations/boot, a ScheduledTask isn't created while the application is still booting, and therefore this issue doesn't occur.

I think this issue could be addressed by tracking the time at which @scheduled_flush is created and then in subsequent invocations of schedule_flush checking if it has been pending far longer than expected. If it is sufficiently stale, then the outstanding ScheduledTask would be cancelled and a new one created. There may be more robust/elegant ways to address this because I'm not particularly familiar with ruby/rails thread management.

Argument Error Invalid log level

There seems to be some issue with the library when used as
config.logger = Logdna::Ruby.new("key", options={} ) as per the README its showing the below error
.rvm/rubies/ruby-2.6.3/lib/ruby/2.6.0/logger.rb:284:in `level=': invalid log level: (ArgumentError)

why output "provide either a message or block" if message is nil?

Was tracking down some mystery "DEBUG -- : provide either a message or block" messages in my logs.

Finally found one reference to it, in another issue here for logdna.

It's a terribly unhelpful message, as it gives zero indication of what gem is outputting it... please MENTION your gem name in such messages.

But more to the point, what is wrong with a nil message?

It seems to me that this code:

logger.info
logger.info
logger.info "NOTICE ME!"
logger.info
logger.info

is legitimate and should output 5 INFO lines to the log, 4 without a text message, NOT 4 cryptic "DEBUG" lines saying "provide either a message or block" messages

I'm not sure where in your code it is, but here's your code that IMO ought be removed, or at least mention the source of the message eg the "logdna gem"

if message.nil?
    @internal_logger.debug("provide either a message or block")
    return
  end

NameError: uninitialized constant Logdna

I've added logdna to my rails 5.2.3 application gemfile and am getting the error whenever I try to use the gem

[4] pry(main)> Logdna::Ruby.new
NameError: uninitialized constant Logdna

Yes, I have bundled.

Logger doesn't support 'add' method

D, [2022-05-01T09:09:23.361998 #45439] DEBUG -- : add not supported in LogDNA logger

This litters our development logs. Any reason why it's been built to not support this operation?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.