Creating an Ansible role for CloudWatch logs

To send our logs to CloudWatch, AWS provides a daemon called awslogs. We are going to install and configure it through Ansible.

Go into your ansible roles directory:

$ cd ansible/roles  

Create a new role called awslogs:

$ ansible-galaxy init awslogs
- awslogs was created successfully  

We will first edit the task file awslogs/tasks/main.yml. Our first operation will be to install the package. For that, we will use the yum module:

--- 
# tasks file for awslogs  

- name: install awslogs yum: name: awslogs state: present

We will want to configure the service dynamically with Ansible. For that, we will want to create a handler to restart awslogs when the configuration changes.

Edit the file awslogs/handlers/main.yml and add the following:

--- 
# handlers file for awslogs 

- name: restart awslogs service: name: awslogs state: restarted

We can now configure the service. You can refer to http://amzn.to/2qMhaEt for the full documentation of the configuration of the service. In our case, we will keep it very simple. The service is configured through a set of INI files. The first one goes into /etc/awslogs/awslogs.conf. We will create the file using the file module from Ansible.

Create a new file in awslogs/files/, call it awslogs.conf, and put the following in it:

[general] 
state_file = /var/lib/awslogs/agent-state 

Now that the file is created, we are going to copy it to its target destination, /etc/awslogs/awslogs.conf. For that, we will use the copy module. Back in the awslogs/tasks/main.yml task file, we will add the following:

- name: copy global configuration 
  copy: 
    src: awslogs.conf 
    dest: /etc/awslogs 
  notify: restart awslogs 

Thanks to the notify handler we created, if we were to change our configuration file, awslogs would automatically restart and, through that, load the new configuration.

We now want to use Ansible to configure which file needs to be collected. We will do that by creating new INI files inside the /etc/awslogs/config directory. To make it easy to operate, we will create one INI file per log file we want to collect. We will take advantage of the INI file module that Ansible provides to implement that. At the bottom of the task file, create a new command as follows:

- name: configure awslogs to collect {{ file }} 
  ini_file: 

We want our role to be generic and able to collect a variety of logs. As such, we will take advantage of the variable system that Ansible provides. The idea is that whenever we call this role, we will provide the information needed, such as the file to collect and its name.

The INI module requires us to provide the path of the INI file we want to configure. We will do that as follows:

    path: "/etc/awslogs/config/{{ name }}.conf" 

Here as well, we are calling the variable name that will be provided when we instantiate the module. The section of the configuration file will be the filename we want to collect:

    section: "{{ file }}" 

Now that the section is created, we are going to configure the different options. We will want to configure six different options. To keep the code dry, we will take advantage of the with_items keyword to iterate over the list of options and values:

    option: "{{ item.option }}" 
    value: "{{ item.value }}" 

Finally, we can list the different options and values as follows:

  with_items: 
    - { option: file, value: "{{ file }}" } 
    - { option: log_group_name, value: "{{ file }}" } 
    - { option: log_stream_name, value: "{instance_id}" } 
    - { option: initial_position, value: "start_of_file" } 
    - { option: buffer_duration, value: "5000" } 
    - { option: datetime_format, value: "{{ datetime_format | default('%b %d %H:%M:%S') }}" } 

Here, too, we rely heavily on the fact that most values will be provided later. Note how we are making the datetime_formatfield optional. If it's not provided, we will try to read our logs as if they were formatted by the syslog. You can refer to the Python datetime.strptime() documentation for the full list of format variables.

We will conclude this call with a notify to restart awslogs if the configuration changed:

  notify: restart awslogs 

The last call of our task file will be to start the service and enable it so that awslogs starts right away, and upon reboot:

- name: start awslogs and enable it 
  service: 
    name: awslogs 
    state: started 
    enabled: yes 

Our role is ready, and we will use it inside our nodeserver.yml file. We will collect /var/log/messages and /var/log/helloworld/helloworld.log. Each entry will have a unique name (messages and helloworld) and their full path. In addition, we need to specify the logging format that our helloworld application is using:

--- 
- hosts: "{{ target | default('localhost') }}" 
  become: yes 
  roles: 
    - nodejs 
    - codedeploy 
    - { role: awslogs, name: messages, file: /var/log/messages }    
- {
role: awslogs,
name: helloworld,
file: /var/log/helloworld/helloworld.log,
datetime_format: "%Y-%m-%dT%H:%M:%S.%f"
}

Your code should be similar to http://bit.ly/2v3bp9G.

Before we commit those changes, we are going to update our CloudFormation template to add proper permissions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset