DEV Community

Germán Alberto Gimenez Silva
Germán Alberto Gimenez Silva

Posted on • Originally published at rubystacknews.com on

Debugging in Real Life: How I Use Rails.logger and Docker Logs in My Daily Workflow

December 1, 2025

Debugging is one of those tasks that quietly shapes a developer’s day. It’s not flashy, it’s not glamorous, but it’s the difference between smooth development and losing an afternoon wondering why a request refuses to behave.

Over the years working with Ruby and Rails, one of the tools I’ve learned to appreciate the most is something surprisingly simple: Rails.logger. And paired with Docker/Docker Compose, it becomes a powerful way to trace, filter, and understand what’s happening inside an application—especially during development and local testing.


Bring Your Next Project to Life with High-Quality Development

Don’t miss the opportunity to take your project to the next level. Whether you want to launch something new or improve an existing platform, we build maintainable, scalable software that empowers your business.

🚀 Available for freelance and team-based projects • Fast replies


Why I Rely on Rails.logger

Article content

Rails has solid built-in logging, but what really gives Rails.logger power is how flexible it is for debugging real scenarios:

1. Quick, precise debugging

When I need to inspect the behavior of a service, model, or background job, I drop logs like:


Rails.logger.debug ">>> Entering OrderProcessor for order_id=#{order.id}"
Rails.logger.info "||| Payment gateway response: #{response.inspect}"
Rails.logger.warn "!!! Missing address for user #{user.id}"
Rails.logger.error "### Unexpected error: #{error.message}"

Enter fullscreen mode Exit fullscreen mode

I like to use visual markers (>>>, |||, !!!, ###) because they’re easy to search when browsing logs. This lets me instantly recognize my debugging entries among the noise of framework or library logs.

2. Choosing the right log level

Rails.logger gives several levels:

  • debug → detailed, step-by-step
  • info → normal workflow
  • warn → something unusual but not critical
  • error → something went wrong but the app keeps running
  • fatal → unrecoverable issues

Using the correct level is not only good discipline—it makes it easier later to filter logs when I need to focus on specific issues.

3. Context matters

I often add tags or identifiers:


Rails.logger.debug("[OrderSync] Started job for order #{order.number}")

Enter fullscreen mode Exit fullscreen mode

This helps when multiple jobs, workers, or API integrations are running at the same time.


When Docker Enters the Game

Working with Docker/Docker Compose brings a different dimension to logs. Instead of reading logs from the Rails console or server output, my workflow shifts to shell commands.

My most common pattern

When I want to inspect logs for a specific service inside a Docker Compose environment, I run:


docker compose logs | grep <application_name> | grep '|||'

Enter fullscreen mode Exit fullscreen mode

Or to improve clarity:


docker compose logs <service_name> | grep '|||'

Enter fullscreen mode Exit fullscreen mode

This practice gives me two benefits:

  1. Instant filtering — I only see the logs I intentionally printed.
  2. Separating services — useful when you have Rails, Sidekiq, Nginx, Postgres, Redis all talking at once.

Why grep markers?

Because when you’re monitoring thousands of lines of logs, a simple pattern like ||| becomes your best friend.

So a log like:


Rails.logger.debug "||| User #{user.id} updated successfully"

Enter fullscreen mode Exit fullscreen mode

Can be extracted in seconds:


docker compose logs web | grep '|||'

Enter fullscreen mode Exit fullscreen mode

Simple. Effective. Reliable.


Small Optimizations I Use Daily

Article content

1. Color-coded timestamps

Useful when reading long traces.


Rails.logger.debug "\e[35m[DEBUG #{Time.now}]||| Sync step reached\e[0m"

Enter fullscreen mode Exit fullscreen mode

2. JSON logs for complex data

When inspecting payloads or external API responses:


Rails.logger.debug "||| Payload: #{payload.to_json}"

Enter fullscreen mode Exit fullscreen mode

Easy to parse, easy to grep.

3. Feature-specific debug blocks

Sometimes I wrap logs under conditional flags:


if ENV["DEBUG_PAYMENTS"]
  Rails.logger.debug "||| PaymentCheck → #{payment.inspect}"
end

Enter fullscreen mode Exit fullscreen mode

This allows me to enable extra verbosity without modifying code again.


The Hidden Value of a Good Logs Strategy

Debugging is not only about fixing errors. It’s also about understanding the system, monitoring behavior, and being able to retrace events when something unexpected happens.

A clear logging strategy allows you to:

  • catch regressions early
  • understand how background workers behave
  • track performance bottlenecks
  • examine external integrations step-by-step
  • reduce time wasted trying to reproduce issues

Good logging is not noise—it’s a conversation with your system.


Final Thoughts

Every developer finds their own debugging style over time. For me, the combination of Rails.logger + Docker logs + meaningful patterns has become part of my daily routine, almost without thinking about it.

It’s a lightweight, flexible, reliable approach that adapts well whether I’m working on Rails controllers, service objects, background jobs, or API integrations.

And honestly, nothing feels better than searching for a log marker and instantly finding the exact moment when something went wrong—or exactly where it went right.

Article content

Top comments (0)