├── templates └── default │ ├── awscli.conf.erb │ └── awslogs.conf.erb ├── attributes └── default.rb ├── metadata.rb ├── recipes ├── default.rb ├── package.rb └── installer.rb └── README.md /templates/default/awscli.conf.erb: -------------------------------------------------------------------------------- 1 | [plugins] 2 | cwlogs = cwlogs 3 | [default] 4 | region = <%= node['cwlogs']['region'] %> 5 | -------------------------------------------------------------------------------- /attributes/default.rb: -------------------------------------------------------------------------------- 1 | default[:cwlogs][:region] = 'us-east-1' 2 | default[:cwlogs][:state_file_dir] = '/var/awslogs/state' 3 | default[:cwlogs][:state_file_name] = 'agent-state' 4 | -------------------------------------------------------------------------------- /metadata.rb: -------------------------------------------------------------------------------- 1 | name 'cwlogs' 2 | maintainer 'Mike Schuette' 3 | maintainer_email 'mike.schuette@gmail.com' 4 | license 'FreeBSD' 5 | description 'Installs and configures AWS CloudWatch Logs' 6 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) 7 | version '0.0.3' 8 | 9 | %w{ ubuntu debian centos redhat fedora }.each do |os| 10 | supports os 11 | end 12 | -------------------------------------------------------------------------------- /recipes/default.rb: -------------------------------------------------------------------------------- 1 | if node['ec2'].nil? 2 | log('Refusing to install CloudWatch Logs because this does not appear to be an EC2 instance.') { level :warn } 3 | return 4 | end 5 | 6 | if node['cwlogs']['logfiles'].nil? 7 | log("Refusing to install CloudWatch Logs because no logs have been configured. (node['cwlogs']['logfiles'] is nil)") { level :warn } 8 | return 9 | end 10 | 11 | if node[:platform] == 'amazon' && Gem::Version.new(node['platform_version']) >= Gem::Version.new('2014.09') 12 | include_recipe 'cwlogs::package' 13 | else 14 | include_recipe 'cwlogs::installer' 15 | end 16 | -------------------------------------------------------------------------------- /recipes/package.rb: -------------------------------------------------------------------------------- 1 | package 'awslogs' do 2 | action :install 3 | end 4 | 5 | directory node['cwlogs']['state_file_dir'] do 6 | owner 'root' 7 | group 'root' 8 | mode 0755 9 | recursive true 10 | action :create 11 | end 12 | 13 | template '/etc/awslogs/awscli.conf' do 14 | source 'awscli.conf.erb' 15 | owner 'root' 16 | group 'root' 17 | mode 0600 18 | end 19 | 20 | template '/etc/awslogs/awslogs.conf' do 21 | source "awslogs.conf.erb" 22 | owner "root" 23 | group "root" 24 | mode 0644 25 | variables ({ 26 | :logfiles => node['cwlogs']['logfiles'] 27 | }) 28 | notifies :restart, 'service[awslogs]' 29 | end 30 | 31 | service 'awslogs' do 32 | supports [:start, :stop, :status, :restart] 33 | action [:enable, :start] 34 | end 35 | -------------------------------------------------------------------------------- /recipes/installer.rb: -------------------------------------------------------------------------------- 1 | service 'awslogs' do 2 | # awslogs service is created, enabled, and started by the installer at the end of this recipe, but we need to declare 3 | # a chef resource for the template to notify 4 | action :nothing 5 | end 6 | 7 | template '/tmp/cwlogs.cfg' do 8 | source 'awslogs.conf.erb' 9 | owner 'root' 10 | group 'root' 11 | mode 0644 12 | variables ({ 13 | :logfiles => node['cwlogs']['logfiles'] 14 | }) 15 | notifies :restart, 'service[awslogs]' 16 | end 17 | 18 | directory '/opt/aws/cloudwatch' do 19 | recursive true 20 | end 21 | 22 | remote_file '/opt/aws/cloudwatch/awslogs-agent-setup.py' do 23 | source 'https://s3.amazonaws.com/aws-cloudwatch/downloads/latest/awslogs-agent-setup.py' 24 | mode '0755' 25 | end 26 | 27 | execute 'Install CloudWatch Logs agent' do 28 | command "/opt/aws/cloudwatch/awslogs-agent-setup.py -n -r #{node['cwlogs']['region']} -c /tmp/cwlogs.cfg" 29 | not_if { system 'pgrep -f aws-logs-agent-setup' } 30 | end 31 | -------------------------------------------------------------------------------- /templates/default/awslogs.conf.erb: -------------------------------------------------------------------------------- 1 | <%= '# NOTE: This config file was generated by chef and will be overwritten at the next chef run!' %> 2 | 3 | [general] 4 | # Path to the AWSLogs agent's state file. Agent uses this file to maintain 5 | # client side state across its executions. 6 | state_file = <%= "#{node['cwlogs']['state_file_dir']}/#{node['cwlogs']['state_file_name']}" %> 7 | 8 | ## Each log file is defined in its own section. The section name doesn't 9 | ## matter as long as its unique within this file. 10 | # 11 | #[kern.log] 12 | ## Path of log file for the agent to monitor and upload. 13 | #file = /var/log/kern.log 14 | ## Name of the destination log group. 15 | #log_group_name = kern.log 16 | ## Name of the destination log stream. 17 | #log_stream_name = {instance_id} 18 | ## Format specifier for timestamp parsing. 19 | #datetime_format = %b %d %H:%M:%S 20 | 21 | <% @logfiles.each do |section_name, section_config| %> 22 | 23 | <%= '[' + section_name + ']' %> 24 | <% section_config.each do |key,val| %> 25 | <%= key %> = <%= val %> 26 | <% end %> 27 | 28 | <% end %> -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Description 2 | =========== 3 | 4 | Installs the CloudWatch Logs client and enables easy configuration of multiple logs via attributes. 5 | 6 | 7 | # Supported OS 8 | Currently all linux OS's are supported. 9 | 10 | On Amazon Linux the yum package will be used. 11 | 12 | # Usage 13 | Logs are configured by appending to the `['cwlogs']['logfiles']` attribute from any recipe. You can configure as many 14 | logs as needed. Simply include the default cwlogs recipe in your runlist after all recipes which define a log. 15 | 16 | 17 | # Example 18 | 19 | default['cwlogs']['logfiles']['mysite-httpd_access'] = { 20 | :log_stream_name => '{instance_id}', 21 | :log_group_name => 'mysite-httpd_access-group', 22 | :file => '/var/log/httpd/mysite.com/access_log', 23 | :datetime_format => '%d/%b/%Y:%H:%M:%S %z', 24 | :initial_position => 'end_of_file' 25 | } 26 | 27 | default['cwlogs']['logfiles']['mysite-httpd_error'] = { 28 | :log_stream_name => '{instance_id}', 29 | :log_group_name => 'mysite-httpd_error-group', 30 | :file => '/var/log/httpd/mysite.com/error_log', 31 | :datetime_format => '%d/%b/%Y:%H:%M:%S %z', 32 | :initial_position => 'end_of_file' 33 | } 34 | 35 | From any attributes file will generate the following CloudWatch Logs config: 36 | 37 | [mysite.com-httpd_access] 38 | log_stream_name = {instance_id} 39 | log_group_name = mysite.com-httpd_access-group 40 | file = /var/log/httpd/mysite.com/access_log 41 | datetime_format = %d/%b/%Y:%H:%M:%S %z 42 | initial_position = end_of_file 43 | 44 | [mysite.com-httpd_error] 45 | log_stream_name = {instance_id} 46 | log_group_name = mysite.com-httpd_error-group 47 | file = /var/log/httpd/mysite.com/error_log 48 | datetime_format = %d/%b/%Y:%H:%M:%S %z 49 | initial_position = end_of_file 50 | 51 | All hash elements will pass through to the config file, so for example you can use `encoding` or any other supported 52 | config element. See the [AWS CloudWatch Logs configuration reference][1] for details. 53 | 54 | [1](http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/AgentReference.html) 55 | --------------------------------------------------------------------------------