2024-08-27 01:53:59 -04:00
{
lib ,
pkgs ,
config ,
. . .
} :
let
cfg = config . services . amazon-cloudwatch-agent ;
tomlFormat = pkgs . formats . toml { } ;
jsonFormat = pkgs . formats . json { } ;
# See https://docs.aws.amazon.com/prescriptive-guidance/latest/implementing-logging-monitoring-cloudwatch/create-store-cloudwatch-configurations.html#store-cloudwatch-configuration-s3.
#
# We don't use the multiple JSON configuration files feature,
# but "config-translator" will log a benign error if the "-input-dir" option is omitted or is a non-existent directory.
#
# Create an empty directory to hide this benign error log. This prevents false-positives if users filter for "error" in the agent logs.
configurationDirectory = pkgs . runCommand " a m a z o n - c l o u d w a t c h - a g e n t . d " { } " m k d i r $ o u t " ;
in
{
options . services . amazon-cloudwatch-agent = {
enable = lib . mkEnableOption " A m a z o n C l o u d W a t c h A g e n t " ;
package = lib . mkPackageOption pkgs " a m a z o n - c l o u d w a t c h - a g e n t " { } ;
2024-11-23 14:26:07 -05:00
commonConfigurationFile = lib . mkOption {
2025-02-05 18:38:51 -05:00
type = lib . types . path ;
default = tomlFormat . generate " c o m m o n - c o n f i g . t o m l " cfg . commonConfiguration ;
defaultText = lib . literalExpression '' t o m l F o r m a t . g e n e r a t e " c o m m o n - c o n f i g . t o m l " c f g . c o m m o n C o n f i g u r a t i o n '' ;
2024-08-27 01:53:59 -04:00
description = ''
Amazon CloudWatch Agent common configuration . See
< https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/install-CloudWatch-Agent-commandline-fleet.html #CloudWatch-Agent-profile-instance-first>
for supported values .
2024-11-23 14:26:07 -05:00
{ option } ` commonConfigurationFile ` takes precedence over { option } ` commonConfiguration ` .
Note : Restricted evaluation blocks access to paths outside the Nix store .
This means detecting content changes for mutable paths ( i . e . not input or content-addressed ) can't be done .
As a result , ` nixos-rebuild ` won't reload/restart the systemd unit when mutable path contents change .
` systemctl restart amazon-cloudwatch-agent . service ` must be used instead .
'' ;
example = " / e t c / a m a z o n - c l o u d w a t c h - a g e n t / a m a z o n - c l o u d w a t c h - a g e n t . j s o n " ;
} ;
commonConfiguration = lib . mkOption {
type = tomlFormat . type ;
default = { } ;
description = ''
See { option } ` commonConfigurationFile ` .
{ option } ` commonConfigurationFile ` takes precedence over { option } ` commonConfiguration ` .
2024-08-27 01:53:59 -04:00
'' ;
example = {
credentials = {
shared_credential_profile = " p r o f i l e _ n a m e " ;
shared_credential_file = " / p a t h / t o / c r e d e n t i a l s " ;
} ;
proxy = {
http_proxy = " h t t p _ u r l " ;
https_proxy = " h t t p s _ u r l " ;
no_proxy = " d o m a i n " ;
} ;
} ;
} ;
2024-11-23 14:26:07 -05:00
configurationFile = lib . mkOption {
2025-02-05 18:38:51 -05:00
type = lib . types . path ;
default = jsonFormat . generate " a m a z o n - c l o u d w a t c h - a g e n t . j s o n " cfg . configuration ;
defaultText = lib . literalExpression '' j s o n F o r m a t . g e n e r a t e " a m a z o n - c l o u d w a t c h - a g e n t . j s o n " c f g . c o n f i g u r a t i o n '' ;
2024-11-23 14:26:07 -05:00
description = ''
Amazon CloudWatch Agent configuration file . See
< https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html >
for supported values .
The following options aren't supported :
* ` agent . run_as_user `
* Use { option } ` user ` instead .
{ option } ` configurationFile ` takes precedence over { option } ` configuration ` .
Note : Restricted evaluation blocks access to paths outside the Nix store .
This means detecting content changes for mutable paths ( i . e . not input or content-addressed ) can't be done .
As a result , ` nixos-rebuild ` won't reload/restart the systemd unit when mutable path contents change .
` systemctl restart amazon-cloudwatch-agent . service ` must be used instead .
'' ;
example = " / e t c / a m a z o n - c l o u d w a t c h - a g e n t / a m a z o n - c l o u d w a t c h - a g e n t . j s o n " ;
} ;
2024-08-27 01:53:59 -04:00
configuration = lib . mkOption {
type = jsonFormat . type ;
default = { } ;
description = ''
2024-11-23 14:26:07 -05:00
See { option } ` configurationFile ` .
{ option } ` configurationFile ` takes precedence over { option } ` configuration ` .
2024-08-27 01:53:59 -04:00
'' ;
# Subset of "CloudWatch agent configuration file: Complete examples" and "CloudWatch agent configuration file: Traces section" in the description link.
#
# Log file path changed from "/opt/aws/amazon-cloudwatch-agent/logs" to "/var/log/amazon-cloudwatch-agent" to follow the FHS.
example = {
agent = {
metrics_collection_interval = 10 ;
logfile = " / v a r / l o g / a m a z o n - c l o u d w a t c h - a g e n t / a m a z o n - c l o u d w a t c h - a g e n t . l o g " ;
} ;
metrics = {
namespace = " M y C u s t o m N a m e s p a c e " ;
metrics_collected = {
cpu = {
resource = [ " * " ] ;
measurement = [
{
name = " c p u _ u s a g e _ i d l e " ;
rename = " C P U _ U S A G E _ I D L E " ;
unit = " P e r c e n t " ;
}
{
name = " c p u _ u s a g e _ n i c e " ;
unit = " P e r c e n t " ;
}
" c p u _ u s a g e _ g u e s t "
] ;
totalcpu = false ;
metrics_collection_interval = 10 ;
append_dimensions = {
customized_dimension_key_1 = " c u s t o m i z e d _ d i m e n s i o n _ v a l u e _ 1 " ;
customized_dimension_key_2 = " c u s t o m i z e d _ d i m e n s i o n _ v a l u e _ 2 " ;
} ;
} ;
} ;
} ;
logs = {
logs_collected = {
files = {
collect_list = [
{
file_path = " / v a r / l o g / a m a z o n - c l o u d w a t c h - a g e n t / a m a z o n - c l o u d w a t c h - a g e n t . l o g " ;
log_group_name = " a m a z o n - c l o u d w a t c h - a g e n t . l o g " ;
log_stream_name = " { i n s t a n c e _ i d } " ;
timezone = " U T C " ;
}
] ;
} ;
} ;
log_stream_name = " l o g _ s t r e a m _ n a m e " ;
force_flush_interval = 15 ;
} ;
traces = {
traces_collected = {
xray = { } ;
oltp = { } ;
} ;
} ;
} ;
} ;
2024-11-23 14:26:07 -05:00
# Replaces "agent.run_as_user" from the configuration file.
user = lib . mkOption {
type = lib . types . str ;
default = " r o o t " ;
description = ''
The user that runs the Amazon CloudWatch Agent .
'' ;
example = " a m a z o n - c l o u d w a t c h - a g e n t " ;
} ;
2024-08-27 01:53:59 -04:00
mode = lib . mkOption {
type = lib . types . str ;
default = " a u t o " ;
description = ''
Amazon CloudWatch Agent mode . Indicates whether the agent is running in EC2 ( " e c 2 " ) , on-premises ( " o n P r e m i s e " ) ,
or if it should guess based on metadata endpoints like IMDS or the ECS task metadata endpoint ( " a u t o " ) .
'' ;
example = " o n P r e m i s e " ;
} ;
} ;
config = lib . mkIf cfg . enable {
2024-11-23 14:26:07 -05:00
# See https://github.com/aws/amazon-cloudwatch-agent/blob/v1.300049.1/packaging/dependencies/amazon-cloudwatch-agent.service.
2024-08-27 01:53:59 -04:00
systemd . services . amazon-cloudwatch-agent = {
description = " A m a z o n C l o u d W a t c h A g e n t " ;
after = [ " n e t w o r k . t a r g e t " ] ;
wantedBy = [ " m u l t i - u s e r . t a r g e t " ] ;
serviceConfig = {
Type = " s i m p l e " ;
# "start-amazon-cloudwatch-agent" assumes the package is installed at "/opt/aws/amazon-cloudwatch-agent" so we can't use it.
#
# See https://github.com/aws/amazon-cloudwatch-agent/issues/1319.
#
# This program:
# 1. Switches to a non-root user if configured.
# 2. Runs "config-translator" to translate the input JSON configuration files into separate TOML (for CloudWatch Logs + Metrics),
# YAML (for X-Ray + OpenTelemetry), and JSON (for environment variables) configuration files.
# 3. Runs "amazon-cloudwatch-agent" with the paths to these generated files.
#
# Re-implementing with systemd options.
2024-11-23 14:26:07 -05:00
User = cfg . user ;
2024-08-27 01:53:59 -04:00
RuntimeDirectory = " a m a z o n - c l o u d w a t c h - a g e n t " ;
LogsDirectory = " a m a z o n - c l o u d w a t c h - a g e n t " ;
2024-11-23 14:26:07 -05:00
ExecStartPre = builtins . concatStringsSep " " [
" ${ cfg . package } / b i n / c o n f i g - t r a n s l a t o r "
2025-02-05 18:38:51 -05:00
" - c o n f i g ${ cfg . commonConfigurationFile } "
" - i n p u t ${ cfg . configurationFile } "
2024-11-23 14:26:07 -05:00
" - i n p u t - d i r ${ configurationDirectory } "
" - m o d e ${ cfg . mode } "
" - o u t p u t \$ { R U N T I M E _ D I R E C T O R Y } / a m a z o n - c l o u d w a t c h - a g e n t . t o m l "
] ;
ExecStart = builtins . concatStringsSep " " [
" ${ cfg . package } / b i n / a m a z o n - c l o u d w a t c h - a g e n t "
" - c o n f i g \$ { R U N T I M E _ D I R E C T O R Y } / a m a z o n - c l o u d w a t c h - a g e n t . t o m l "
" - e n v c o n f i g \$ { R U N T I M E _ D I R E C T O R Y } / e n v - c o n f i g . j s o n "
" - o t e l c o n f i g \$ { R U N T I M E _ D I R E C T O R Y } / a m a z o n - c l o u d w a t c h - a g e n t . y a m l "
" - p i d f i l e \$ { R U N T I M E _ D I R E C T O R Y } / a m a z o n - c l o u d w a t c h - a g e n t . p i d "
] ;
2024-08-27 01:53:59 -04:00
KillMode = " p r o c e s s " ;
Restart = " o n - f a i l u r e " ;
RestartSec = 60 ;
} ;
} ;
} ;
}