DEV Community

Ken Collins for AWS Heroes

Posted on • Edited on

Using New Relic APM with Rails on AWS Lambda

ℹ️ 2021-07-06 - Updated code block with LambdaPunch asynchronous background job processing.

Custom Ink has been using Rails for as long as the framework has been around. For many of those years we have used New Relic's awesome Application Performance Monitoring (APM) tool to observe and debug dozens of our critical services.

In the past I have have shared on Twitter that that New Relic Ruby Agent did not work when using Rails on AWS Lambda. I think my assumption was based on how the agent's collector needed a daemon process on the server or was tightly coupled to certain web servers like Passenger and thus not compatible with Lamby's Rack adapter under API Gateway.

Thankfully I was wrong! Here is how we got New Relic & Rails working this past week with Lamby.

  1. Use the NEWRELIC_LICENSE_KEY environment variable. This will ensure that the RPM gem can assign it to the license_key config as needed during initialization. Ensure this is present before Rails loads.
  2. Add the log_file_path: STDOUT to your config yaml file.
  3. Optionally, ensure that New Relic flushes your data after each request.

When your Lambda experiences a cold start, the agent should log that it too is starting and using Rack and whatever instrumentation hooks it finds within your application. Here is an example of the config/newrelic.yml file.

common: &default_settings
  app_name: MyAppName
  log_level: fatal
  log_file_path: STDOUT
  ssl: true

development:
  <<: *default_settings
  monitor_mode: false

test:
  <<: *default_settings
  monitor_mode: false

production:
  <<: *default_settings
Enter fullscreen mode Exit fullscreen mode

Now add the LambdaPunch gem to your project and change the handler method to ensure data is flushed to New Relic after each request. LambdaPunch ensures this happens after your Rails application response is sent.

def handler(event:, context:)
  Lamby.handler $app, event, context
ensure
  LambdaPunch.push { NewRelic::Agent.agent.flush_pipe_data }
end
Enter fullscreen mode Exit fullscreen mode

Lastly, thanks so much to the New Relic team for always improving their products and providing an awesome service.

Top comments (4)

Collapse
 
andrewbrown profile image
Andrew Brown 🇨🇦

I used to use New Relic for my Rails apps and loved it, then a few years went by, new start-up and the new pricing for New Relic became higher upfront, so I switched to DataDog's APM because it scaled with the business.

I'm curious if New Relic's pricing is still a barrier for early projects for cost.

I didn't know about your Lamby project. I am trying to wrap my head around it. There's Ruby on Jets so uncertain if this is a project to run Rails on Lambda or Makes it easier to run lambda functions alongside a Rails app, and by easy its the fact that the lambda is loaded with Rails functionality? I ask because as you know Rails is my stack.

lamby.custominktech.com/docs/quick...

Collapse
 
andrewbrown profile image
Andrew Brown 🇨🇦 • Edited

reddit.com/r/rails/comments/gafh0n...

Okay, so after some digging I have clarity

So Lamby and Ruby on Jets both allow you to run Rails apps powered by AWS Lambda.

Ruby on Jets was written prior to Lambda Ruby support.

I am going to have quite a bit of fun digging through the codebase.

Collapse
 
metaskills profile image
Ken Collins • Edited

Hey Andrew! Thanks for stopping by. A few things.

I used to use New Relic for my Rails apps and loved it, then a few years went by, new start-up and the new pricing for New Relic became higher... I'm curious if New Relic's pricing is still a barrier

So they have a free plan and I really do like their turn key APM. But honestly, not the price. As we have been moving Rails applications (high traffic micro to small services) to Lambda we have been removing New Relic and using a mix of CloudWatch Managed Metrics (API Gateway & Lambda) along with CloudWatch Embedded Metrics. I wrote the ruby gem for it. See here github.com/customink/aws-embedded-...

If you have not done so... once you start using CloudWatch Embedded Metrics, you get addicted. So easy with Rails to add Controller#action as a dimension and then add other deep properties or metrics to enhance those for use in CloudWatch Dashboards & Log Insights queries.

So Lamby and Ruby on Jets both allow you to run Rails apps powered by AWS Lambda.

Very familiar with Jets. The methodologies between it and Lamby are drastically different. Lamby is a simple Rack adapter for API Gateway. It basically means API Gateway is now a commoditized web server for Rails. When Jets was done there was no such thing as even a Ruby runtime. So their decisions and work was different. Jets took the sledgehammer approach to Rails and Lambda too... smash it up so every Controller#action is a function. Which made sense back in the day... to some.

Truth be told, I use Lambda for altruistic microservice functions. But I always believe Lambda will move to a commodity compute platform and that full applications can reside within it just fine. No need to smash a small to medium size Rails app up. Just deploy the whole thing in such a way where it has no clue (internally) is runs under API Gateway. I could share more, but please do have fun talking a look around. Ping me on Twitter if you need anything.

Collapse
 
d3 profile image
D3

Thank you @metaskills for this guide.

It seems to work, but with one downside - if using the implementation as per Lambda Punch guide, then it does not send info to New Relic:

def handler(event:, context:)
  Lamby.handler $app, event, context, rack: :http
ensure
  LambdaPunch.push { NewRelic::Agent.agent.flush_pipe_data }
  LambdaPunch.handled!(context)
end
Enter fullscreen mode Exit fullscreen mode

But when omitting LambdaPunch.handled!(context) as per your guide, requests take up additional 2s :)

Did you face same drawbacks or were you able to somehow overcome them?