awscr-cloudwatch v1.0.0

A low-level Crystal client for AWS CloudWatch

awscr-cloudwatch

A low-level Crystal client for AWS CloudWatch:

  1. Metrics: publish counters and other data points, query statistics
  2. Alarms: create, inspect and delete metric and composite alarms

Dashboards, anomaly detectors, tags, metric streams and Contributor Insights rules are covered as well, but with less testing and should be considered experimental only.

For day-to-day use the easy-awscr library is recommended. It handles credentials, connection pooling and provides higher-level APIs like aggregating counters before uploading them.

Installation

  1. Add the dependency to your shard.yml:

    dependencies:
      awscr-cloudwatch:
        github: philipp-classen/awscr-cloudwatch
    
  2. Run shards install

Usage

require "awscr-cloudwatch"

client = Awscr::CloudWatch::Client.new("us-east-1", "key", "secret")
# With temporary credentials: Client.new("us-east-1", "key", "secret", "session_token")

Publishing metrics

metrics = client.metrics

# One counter increment
metrics.put_counter("MyApp", "Requests", dimensions: {"Env" => "prod"})

# Several data points in one request (up to 1000 metrics / 1 MB)
metrics.put_metric_data("MyApp", [
  Awscr::CloudWatch::MetricDatum.counter("Requests", 42, {"Env" => "prod"}),
  Awscr::CloudWatch::MetricDatum.new("Latency", values: [1.5, 2.5], counts: [20.0, 1.0], unit: "Milliseconds"),
  Awscr::CloudWatch::MetricDatum.new("BatchSize", unit: "Count",
    statistic_values: Awscr::CloudWatch::StatisticSet.new(sample_count: 4, sum: 10, minimum: 1, maximum: 4)),
])

Calls return nil on success and raise Awscr::CloudWatch::ApiException when AWS rejects the request. Throttling, 5xx responses and connection errors are retried with exponential backoff (max_attempts: 3 by default).

Querying metrics

stats = metrics.get_metric_statistics("MyApp", "Requests",
  start_time: Time.utc - 1.hour, end_time: Time.utc, period: 5.minutes,
  statistics: ["Sum"], dimensions: {"Env" => "prod"})
stats.datapoints.each { |dp| puts "#{dp.timestamp}: #{dp.sum}" }

data = metrics.get_metric_data([
  Awscr::CloudWatch::MetricDataQuery.new("requests",
    metric_stat: Awscr::CloudWatch::MetricStat.new(Awscr::CloudWatch::Metric.new("MyApp", "Requests"), 5.minutes, "Sum")),
  Awscr::CloudWatch::MetricDataQuery.new("per_second", expression: "requests / 300"),
], start_time: Time.utc - 1.hour, end_time: Time.utc)
data.metric_data_results.each { |r| puts "#{r.id}: #{r.values}" }

metrics.list_metrics(namespace: "MyApp").metrics.each { |m| puts m.metric_name }

Periods are Time::Spans. CloudWatch accepts multiples of one minute, plus 1, 5, 10, 20 and 30 seconds for high-resolution metrics. Anything else raises ArgumentError before a request is sent.

Alarms

alarms = client.alarms

alarms.put_metric_alarm("MyApp-HighErrorRate",
  namespace: "MyApp", metric_name: "Errors", statistic: "Sum", period: 1.minute,
  evaluation_periods: 3, threshold: 100, comparison_operator: "GreaterThanThreshold",
  alarm_actions: ["arn:aws:sns:us-east-1:123456789012:oncall"])

alarms.describe_alarms(alarm_name_prefix: "MyApp-").metric_alarms.each do |alarm|
  puts "#{alarm.alarm_name}: #{alarm.state_value}"
end

alarms.delete_alarms(["MyApp-HighErrorRate"])

MetricClient and AlarmClient can also be used on their own; they take the same constructor arguments as Client.

Custom endpoint and HTTP clients

# Local mock such as Ministack
client = Awscr::CloudWatch::Client.new("us-east-1", "dummy", "dummy", endpoint: "http://localhost:4566")

# Shorter timeouts (defaults: 15 s to connect, 60 s to read)
factory = Awscr::CloudWatch::DefaultHttpClientFactory.new(connect_timeout: 5.seconds, read_timeout: 10.seconds)
client = Awscr::CloudWatch::Client.new("us-east-1", "key", "secret", client_factory: factory)

# Connection pooling: subclass HttpClientFactory (acquire_client / release)

Development

crystal spec
crystal run lib/ameba/bin/ameba.cr

Integration specs only run with AWSCR_CLOUDWATCH_INTEGRATION=1. Against a local mock such as Ministack (which does not fully conform to the AWS API, so just the basic specs pass: uploads, dashboards, connection reuse):

export AWS_ENDPOINT_URL=http://localhost:4566
export AWSCR_CLOUDWATCH_INTEGRATION=1

crystal spec spec/integration

Against a real account:

AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_REGION=us-east-1
AWSCR_CLOUDWATCH_INTEGRATION=1
AWSCR_CLOUDWATCH_TEST_PREFIX=my-test

crystal spec spec/integration

Be careful: this creates alarms, a dashboard and an anomaly detector under the test prefix, and published metrics cannot be deleted.

Contributing

  1. Fork it (https://github.com/philipp-classen/awscr-cloudwatch/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors

Repository

awscr-cloudwatch

Owner
Statistic
  • 0
  • 0
  • 0
  • 1
  • 2
  • 12 days ago
  • September 19, 2026
License

MIT License

Links
Synced at

Thu, 01 Oct 2026 09:09:15 GMT

Languages