AWS Rust SDK を使用したカスタムメトリクスの作成
はじめに
Rust は、安全性、パフォーマンス、並行処理に重点を置いたシステムプログラミング言語で、ソフトウェア開発の世界で人気を集めています。 メモリ管理とス レッドの安全性に対するユニークなアプローチにより、堅牢で効率的なアプリケーションの構築に適しており、特にクラウドでの利用に適しています。 サーバーレスアーキテクチャの台頭と、高性能でスケーラブルなサービスへのニーズの高まりにより、Rust の機能はクラウドネイティブアプリケーションの構築に最適な選択肢となっています。 このガイドでは、AWS Rust SDK を活用してカスタム CloudWatch メトリクスを作成し、AWS エコシステム内でアプリケーションのパフォーマンスと動作についてより深い洞察を得る方法を探ります。
前提条件
このガイドを使用するには、Rust をインストールし、後で使用するデータを保存するための CloudWatch ロググループとログストリームを作成する必要があります。
Rust のインストール
Mac または Linux の場合:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Windows の場合は、rustup-init.exe をダウンロードして実行してください。
CloudWatch ロググループとログストリームの作成
- CloudWatch ロググループを作成します:
aws logs create-log-group --log-group-name rust_custom
- CloudWatch ログストリームを作成します:
aws logs create-log-stream --log-group-name rust_custom --log-stream-name diceroll_log_stream
コード
完全なコードは、このリポジトリの sandbox セクションにあります。
git clone https://github.com/aws-observability/observability-best-practices.git
cd observability-best-practices/sandbox/rust-custom-metrics
このコードではまず、サイコロを振るシミュレーションを行います。このサイコロの値をカスタムメトリクスとして扱います。 そして、このメトリクスを CloudWatch に追加し、ダッシュボードで表示する 3 つの異なる方法を紹介します。
アプリケーションのセットアップ
まず、アプリケーションで使用するクレートをインポートする必要があります。
use crate::cloudwatch::types::Dimension;
use crate::cloudwatchlogs::types::InputLogEvent;
use aws_sdk_cloudwatch as cloudwatch;
use aws_sdk_cloudwatch::config::BehaviorVersion;
use aws_sdk_cloudwatch::types::MetricDatum;
use aws_sdk_cloudwatchlogs as cloudwatchlogs;
use rand::prelude::*;
use serde::Serialize;
use serde_json::json;
use std::time::{SystemTime, UNIX_EPOCH};
このインポートブロックでは、主に使用する AWS SDK ライブラリをインポートしています。 また、ランダムなサイコロの値を生成するために 'rand' クレートも導入しています。 最後に、SDK 呼び出しで使用するデータ作成を処理するために、'serde' や 'time' などのライブラリも導入しています。
次に、main 関数でサイコロの値を作成できます。この値は、実行する 3 つの AWS SDK 呼び出しすべてで使用されます。
//select a random number 1-6 to represent a diceroll
let mut rng = rand::thread_rng();
let roll_value = rng.gen_range(1..7);
サイコロの数値が得られたので、この値を CloudWatch にカスタムメトリクスとして追加する 3 つの異なる方法を見ていきましょう。 値がカスタムメトリクスになると、その値にアラームを設定したり、異常検出を設定したり、ダッシュボードにプロットしたりなど、さまざまなことができるようになります。
Put Metric Data
最初に使用するメトリクスを CloudWatch に追加する方法は PutMetricData です。PutMetricData を使用すると、メトリクスの時系列の値を CloudWatch に直接書き込むことができます。これが値を追加する最も効率的な方法です。PutMetricData を使用する場合、メトリクス値と共に名前空間とディメンションを各 AWS SDK 呼び出しに提供する必要があります。以下がそのコードです:
まず、メトリクス(サイコロの値)を受け取り、Result 型を返す関数を設定します。Rust では Result 型は成功または失敗を示します。関数内で最初に行うのは、AWS Rust SDK クライアントの初期化です。クライアントはローカル環境から認証情報とリージョンを継承します。このコードを実行する前に、コマンドラインから aws configure
を実行して、これらが設定されていることを確認してください。
async fn put_metric_data(roll_value: i32) -> Result<(), cloudwatch::Error> {
//Create a reusable aws config that we can pass to our clients
let config = aws_config::load_defaults(BehaviorVersion::v2023_11_09()).await;
//Create a cloudwatch client
let client = cloudwatch::Client::new(&config);
クライアントの初期化後、PutMetricData API 呼び出しに必要な入力の設定を開始できます。ディメンションを定義し、その後、ディメンションと値の組み合わせである MetricDatum 自体を定義する必要があります。
//Use fluent builders to build the required input for pmd call, starting with dimensions.
let dimensions = Dimension::builder()
.name("roll_value_pmd_dimension")
.value(roll_value.to_string())
.build();
let put_metric_data_input = MetricDatum::builder()
.metric_name("roll_value_pmd")
.dimensions(dimensions)
.value(f64::from(roll_value))
.build();
最後に、先ほど定義した入力を使用して PutMetricData API を呼び出すことができます。
let response = client
.put_metric_data()
.namespace("rust_custom_metrics")
.metric_data(put_metric_data_input)
.send()
.await?;
println!("Metric Submitted: {:?}", response);
Ok(())
SDK の呼び出しが非同期関数内にあることに注意してください。関数は非同期で完了するため、完了を await
する必要があります。その後、関数の最上位で定義された Result 型を返します。
main から関数を呼び出す時は、以下のようになります:
//call the put_metric_data function with the roll value
println!("First we will write a custom metric with PutMetricData API call");
put_metric_data(roll_value).await.unwrap();
ここでも関数呼び出しの完了を待ち、値を unwrap
します。この場合、エラーではなく 'Ok' の結果にのみ興味があるためです。本番環境のシナリオでは、おそらく異なる方法でエラー処理を行うことになるでしょう。
PutLogEvent + メトリクスフィルター
カスタムメトリクスを作成する次の方法は、CloudWatch ロググループに直接書き込むことです。メトリクスが CloudWatch ロググループに書き込まれたら、メトリクスフィルター を使用してログデータからメトリクスデータを抽出できます。
まず、ログメッセージ用の構造体を定義します。これは任意の手順で、手動で JSON を構築することもできます。しかし、より複雑なアプリケーションでは、再利用性のためにこのようなログ構造体が必要になるでしょう。
//ログメッセージ用のシンプルな構造体を作成します。手動で JSON 文字列を作成することもできます。
#[derive(Serialize)]
struct DicerollValue {
welcome_message: String,
roll_value: i32,
}
構造体を定義したら、AWS API の呼び出しを行う準備が整います。今回も API クライアントを作成しますが、今回は logs SDK を使用します。また、Unix エポックタイミングを使用してシステム時刻を定義します。
//Create a reusable aws config that we can pass to our clients
let config = aws_config::load_defaults(BehaviorVersion::v2023_11_09()).await;
//Create a cloudwatch logs client
let client = cloudwatchlogs::Client::new(&config);
//Let's get the time in ms from unix epoch, this is required for CWlogs
let time_now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis() as i64;