You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Dead-simple structured logging in ruby with a dead-simple codebase. No dependencies, everything logs to stdout, and simple hooks to customize. That’s it.
gem'simple_structured_logger'
Usage
You can use this logger anywhere. Class methods, instance methods, use it as a logger for libraries, etc.
Some examples:
# in a console or simple scriptincludeSimpleStructuredLoggerlog.info'core message',key: Time.now.to_i# in class & instance methodsclassLoggingInModuleincludeSimpleStructuredLoggerdefself.log_somethinglog.info'including the module enables a class and instance method',key: Time.now.to_ienddeflog_something_elselog.info'the class and instance method share the same logging context',key: Time.now.to_iendend# So, how do I set the context? How can I customize how it's set?SimpleStructuredLogger.configuredoexpand_contextdo |context|
# you can pass in a object and use `expand_context` to extract the relevant keysifcontext[:user]context[:user_id]=context[:user].idcontext[:user_name]=context[:user].nameendcontextendendclassExampleJobdefperform(user_id)user=get_user(user_id,job_argument)log.set_context(user: user,job: self.class,job_argument: job_argument)log.info'the log will contain the user_id, job_argument, and job class'# you can also add additional default pairs without resetting contextlog.default_tags[:something]='else'endend# Can you pass object arguments as values and automatically expand them? Well, yes, you can!SimpleStructuredLogger.configuredoexpand_logdo |tags,default_tags|
iftags[:stripe_resource] && tags[:stripe_resource].respond_to?(:id)stripe_resource=tags.delete(:stripe_resource)tags[:stripe_resource_id]=stripe_resource.idtags[:stripe_resource_type]=stripe_resource.class.to_send# this is a really nice pattern I like to use. The `metric` key can trigger a call out to your observability toolingiftags[:metric]dimensions=default_tags.slice(:stripe_user_id,:other_default_tag)metrics.track_counter(tags[:metric],dimensions: dimensions)endtagsendend# want simple formatting? You got it!SimpleStructuredLogger.logger.formatter=procdo |severity,_datetime,_progname,msg|
"#{severity}: #{msg}\n"end# Configure the logger directly if you need toSimpleStructuredLogger.logger.level(Logger::INFO)
Want to change the log level quickly? Without modifying source?
LOG_LEVEL=DEBUG ruby your_script.rb
# case does not matter
LOG_LEVEL=info ruby your_script.rb
Design Goals
Extremely simple codebase that’s easy to read and override
Structured logging that reads nicely and is easy to filter using grep or something like Papertrail
Ability to easily set context, and expand context with user-configurable hook
Ability to easily add structured log pre-processing. I want to be able to pass
in an object specific to my application and for the relevant important keys to
be expanded automatically.
Rails.logger = SimpleStructuredLogger.new(STDOUT)
Not designed around massive systems or scale: no JSON logging, multiple log destinations, and other fanciness.
Don’t build in fancy pre-processing for errors or other common ruby objects
Opinionated Devops Setup
Errors are tracked using Rollbar, Airbrake, Sentry, etc.
Tagged logging is not structured logging. I want to be able to search through
PaperTrail/Splunk/etc and easily grab an audit trail for a specific context, i.e. the_job=FailingJob the_user=1.
Testing
bundle exec rake
TODO
Support logs as blocks?
About
An incredibly simple, very opinionated, structured logging library for ruby