Rails – Custom CloudWatch Application Logs on Elastic Beanstalk

I recently ran into a scenario where I was hosting a Ruby on Rails application on AWS Elastic Beanstalk, and I wanted to view a live stream of the application’s log from within CloudWatch.

For some reason, Elastic Beanstalk doesn’t enable this functionality by default. When you enable CloudWatch streaming on your Elastic Beanstalk environment, it only sends the basic eb-activity.log, passenger.log, and your nginx access/error logs (which aren’t particularly useful).

I did a lot of googling, and cobbled together a solution to the problem by piecing together information from probably around a hundred different pages/forum posts/documentation pages. I have to say, it was rather annoying how difficult it was to figure out something that should have been so simple!

In this scenario, I have two separate environments (one named “production”, and another named “staging”). Each environment has an environment variable called “RAILS_ENV” with its own environment name set on it. The server is configured by Elastic Beanstalk so that it symlinks the Rails application log to “/var/app/support/logs/{environment_name}.log”, and Elastic Beanstalk automatically rotates those logs.

To enable log streaming for the Rails application log, I created a config file in my project at “.ebextensions/configure_logging.config” with these contents:

 

3 comments

  • Thanks a lot for the summary of your research (I know how painful this is quite often!). I used it for my Python environment, the path for the environment variables is different (/opt/python/current/env) and also the location of my Django logs (/opt/python/log/django.log), but the rest I could use as is. AWS gave me a warning when I created the policy regarding “logs:PutLogEvents”, but I see the same policy was used in several other descriptions for making specific logs available in CloudWatch

  • Thank you for sharing this!

    In my case I had to make few adjustments, since the region setting must be set also and my linux 2 environment did not have awslog but awslogd instead.

    Below is adjusted version which yielded desired results for me.


    option_settings:
    - namespace: aws:elasticbeanstalk:cloudwatch:logs
    option_name: StreamLogs
    value: true
    - namespace: aws:elasticbeanstalk:cloudwatch:logs
    option_name: DeleteOnTerminate
    value: false
    - namespace: aws:elasticbeanstalk:cloudwatch:logs
    option_name: RetentionInDays
    value: 7

    # Enable custom logging
    files:
    "/etc/awslogs/config_disabled/beanstalklogs_production.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
    [/var/app/containerfiles/logs/production.log]
    log_group_name =
    {“Fn::Join”:[“/”, [“/aws/elasticbeanstalk”, { “Ref”:”AWSEBEnvironmentName” }, “logger”]]}
    log_stream_name = {instance_id}
    file = /var/app/containerfiles/logs/production.log*

    "/etc/awslogs/config_disabled/beanstalklogs_sandbox.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
    [/var/app/containerfiles/logs/sandbox.log]
    log_group_name =
    {“Fn::Join”:[“/”, [“/aws/elasticbeanstalk”, { “Ref”:”AWSEBEnvironmentName” }, “logger”]]}
    log_stream_name = {instance_id}
    file = /var/app/containerfiles/logs/sandbox.log*

    "/etc/awslogs/config_disabled/awscli.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
    [plugins]
    cwlogs = cwlogs
    [default]
    region = eu-west-1

    # Files in the location /opt/elasticbeanstalk/addons/logstreaming/hooks/
    # are executed after the app has been deployed & the logstreaming addon has been configured
    "/opt/elasticbeanstalk/addons/logstreaming/hooks/config/99-restart-service.sh":
    content : |
    #!/bin/bash
    service awslogsd restart
    mode : "000755"
    owner : root
    group : root

    # This copies and enables the custom logging config file that matches the current RAILS_ENV environment variable,
    # and it also restarts the awslogs service, once the config file is in place.
    commands:
    01_copy_over_logging_config:
    command: 'cp -f "/etc/awslogs/config_disabled/awscli.conf" "/etc/awslogs/awscli.conf"'
    02_enable_logging_config:
    command: 'export RAILS_ENV=$(/opt/elasticbeanstalk/bin/get-config environment -k "RAILS_ENV") && cp -f "/etc/awslogs/config_disabled/beanstalklogs_$RAILS_ENV.conf" "/etc/awslogs/config/beanstalklogs_$RAILS_ENV.conf"'
    03_check_config:
    command: chkconfig awslogsd on
    04_restart_awslogs:
    command: service awslogsd restart

    • Formatting went to sh*t 😀

      option_settings:
      – namespace: aws:elasticbeanstalk:cloudwatch:logs
      option_name: StreamLogs
      value: true
      – namespace: aws:elasticbeanstalk:cloudwatch:logs
      option_name: DeleteOnTerminate
      value: false
      – namespace: aws:elasticbeanstalk:cloudwatch:logs
      option_name: RetentionInDays
      value: 7

      # Enable custom logging
      files:
      “/etc/awslogs/config_disabled/beanstalklogs_production.conf”:
      mode: “000644”
      owner: root
      group: root
      content: |
      [/var/app/containerfiles/logs/production.log]
      log_group_name = {"Fn::Join":["/", ["/aws/elasticbeanstalk", { "Ref":"AWSEBEnvironmentName" }, "logger"]]}
      log_stream_name = {instance_id}
      file = /var/app/containerfiles/logs/production.log*

      “/etc/awslogs/config_disabled/beanstalklogs_sandbox.conf”:
      mode: “000644”
      owner: root
      group: root
      content: |
      [/var/app/containerfiles/logs/sandbox.log]
      log_group_name = {"Fn::Join":["/", ["/aws/elasticbeanstalk", { "Ref":"AWSEBEnvironmentName" }, "logger"]]}
      log_stream_name = {instance_id}
      file = /var/app/containerfiles/logs/sandbox.log*

      “/etc/awslogs/config_disabled/awscli.conf”:
      mode: “000644”
      owner: root
      group: root
      content: |
      [plugins]
      cwlogs = cwlogs
      [default]
      region = eu-west-1

      # Files in the location /opt/elasticbeanstalk/addons/logstreaming/hooks/
      # are executed after the app has been deployed & the logstreaming addon has been configured
      “/opt/elasticbeanstalk/addons/logstreaming/hooks/config/99-restart-service.sh”:
      content : |
      #!/bin/bash
      service awslogsd restart
      mode : “000755”
      owner : root
      group : root

      # This copies and enables the custom logging config file that matches the current RAILS_ENV environment variable,
      # and it also restarts the awslogs service, once the config file is in place.
      commands:
      01_copy_over_logging_config:
      command: ‘cp -f “/etc/awslogs/config_disabled/awscli.conf” “/etc/awslogs/awscli.conf”‘
      02_enable_logging_config:
      command: ‘export RAILS_ENV=$(/opt/elasticbeanstalk/bin/get-config environment -k “RAILS_ENV”) && cp -f “/etc/awslogs/config_disabled/beanstalklogs_$RAILS_ENV.conf” “/etc/awslogs/config/beanstalklogs_$RAILS_ENV.conf”‘
      03_check_config:
      command: chkconfig awslogsd on
      04_restart_awslogs:
      command: service awslogsd restart

Leave a Reply to Dmitry D.D. Cancel reply

Your email address will not be published. Required fields are marked *

Are you a real person? *