Terraform Provider
The LogStruct Terraform provider builds CloudWatch Logs filter patterns for LogStruct's log lines from a source (src) and an event (evt). The plan fails if no LogStruct line has that source and event, so a typo or a removed event is caught before anything is deployed.
Installation
Add the provider to required_providers. It has no settings, so it needs no provider block.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
logstruct = {
source = "DocSpring/logstruct"
version = "~> 0.2.0"
}
}
}The AWS provider is only needed for the module below, which creates an aws_cloudwatch_log_metric_filter. The module asks for the LogStruct provider >= 0.1.0, so your constraint above decides the version.
CloudWatch Metric Filter
The metric-filter module counts the lines with a source and an event: each matching line adds 1 to the metric. Its inputs are name, log_group_name, log_source, log_event, namespace and an optional metric_name (by default <log_source>_<log_event>, here mailer_delivered). It outputs the pattern it used.
module "email_delivered_count" {
source = "DocSpring/logstruct/aws//modules/metric-filter"
version = "~> 0.1.0"
name = "Email Delivered Count"
log_group_name = var.log_group_name
log_source = "mailer"
log_event = "delivered"
namespace = var.namespace
}variable "log_group_name" { type = string }
variable "namespace" { type = string }What the Provider Checks
- The provider has a catalog of LogStruct's sources and the events each one writes, compiled into the provider. Each provider release is built from the LogStruct release with the same version number.
- It never looks at your app or the gem version your app runs. Upgrading the gem changes nothing in Terraform; a plan can only start failing when you upgrade the provider and your source and event are no longer in its catalog.
- An unknown source or event fails the plan:
Error: Invalid event event deliverd is not allowed for source mailer Error: Unknown source No structs found with fixed source = payments - The pattern matches
srcandevtonly, for example{ $.evt = "delivered" && $.src = "mailer" }. Lines from different integrations with the same source and event match the same pattern: ActiveJob's and GoodJob's error lines both havesrc: "job"andevt: "error". - The catalog only has sources with a fixed set of events, so it has no pattern for the general error lines (such as
src: "app",evt: "error") or for your own custom log types. Write those patterns yourself, as in the last recipe below.
Versioning
- Provider versions match LogStruct's: provider
0.2.0has the sources and events of LogStruct0.2.0. - Use
~> 0.2.0to get0.2.xreleases only. Below 1.0,~> 0.2also allows0.3and later, and a minor release can remove events:0.2.0removed GoodJob'senqueue,start,finishandschedule, which GoodJob never wrote (its jobs' lines come from ActiveJob, with the same source and events).
Recipes
Count email deliveries
module "email_delivered_count" {
source = "DocSpring/logstruct/aws//modules/metric-filter"
version = "~> 0.1.0"
name = "Email Delivered Count"
log_group_name = var.log_group_name
log_source = "mailer"
log_event = "delivered"
namespace = var.namespace
}Count mailer errors
LogStruct writes a mailer error line when a mailer raises an error, as when a delivery fails.
module "mailer_error_count" {
source = "DocSpring/logstruct/aws//modules/metric-filter"
version = "~> 0.1.0"
name = "Mailer Error Count"
log_group_name = var.log_group_name
log_source = "mailer"
log_event = "error"
namespace = var.namespace
}Count finished ActiveJob runs
ActiveJob writes a finish line when a job's perform returns. That includes a run whose exception retry_on or discard_on handled, which also has a retry or discard line. A run that raises has an error line instead.
module "job_finish_count" {
source = "DocSpring/logstruct/aws//modules/metric-filter"
version = "~> 0.1.0"
name = "ActiveJob Finish Count"
log_group_name = var.log_group_name
log_source = "job"
log_event = "finish"
namespace = var.namespace
}Count slow SQL queries
SQL lines are off by default (enable_sql_logging). When they're on, LogStruct writes one for each query that takes at least sql_slow_query_threshold milliseconds (100 by default).
module "slow_sql_count" {
source = "DocSpring/logstruct/aws//modules/metric-filter"
version = "~> 0.1.0"
name = "Slow SQL Query Count"
log_group_name = var.log_group_name
log_source = "app"
log_event = "database"
namespace = var.namespace
}Use the data sources directly
The module uses the provider's two data sources. logstruct_pattern takes a source and an event and returns the pattern. logstruct_source takes a source and returns it as canonical, with the source's events as a map. Use them to build your own metric filters or subscription filters:
data "logstruct_source" "mailer" {
source = "mailer"
}
data "logstruct_pattern" "email_delivered" {
source = data.logstruct_source.mailer.canonical
event = "delivered"
}
resource "aws_cloudwatch_log_metric_filter" "email_delivered" {
name = "Email Delivered Count"
log_group_name = var.log_group_name
pattern = data.logstruct_pattern.email_delivered.pattern
metric_transformation {
name = "mailer_delivered"
namespace = var.namespace
value = "1"
unit = "Count"
}
}Match on other fields
CloudWatch's JSON filter patterns can compare numbers, but the provider only builds src and evt patterns. Write a pattern with other fields yourself:
resource "aws_cloudwatch_log_metric_filter" "very_slow_sql" {
name = "Very Slow SQL Query Count"
log_group_name = var.log_group_name
pattern = "{ $.src = \"app\" && $.evt = \"database\" && $.duration_ms > 1000 }"
metric_transformation {
name = "sql_very_slow"
namespace = var.namespace
value = "1"
unit = "Count"
}
}To chart the durations instead of counting the lines, set value to "$.duration_ms".