Sentryに対する印象として、よく聞かれるのは「アプリケーションのエラートラッキング」です。もちろん、Webアプリケーションやモバイルアプリケーションに対してSDKをインストールするだけで使えるエラートラッキングはSentryの大きな強みです。
しかし、ここ数年でSentryに対して期待される役割が膨らんでいます。アプリケーションはエラー(例外処理)だけが問題ではなく、パフォーマンスの劣化や、複雑な操作の結果としてのエラー発生が日常的に発生します。また、エラーはアプリケーション層だけでなく、バックエンドやデータベースなども組み合わさって発生します。
そうした現実的な課題に合わせて、Sentryでは機能拡張が行われています。我々の目指すのは、アプリケーションも含めたフルスタックのオブザーバビリティサービスです。
オブザーバビリティの基本
オブザーバビリティはObserve(観察する)とAbility(能力)を組み合わせた造語で、日本語では可観測性と呼ばれます。システム内部の複雑な状態を分析、可視化します。それによって、問題が発生した際に素早く解決したり、未然に防ぐことが可能です。
オブザーバビリティは以下の3要素が基本になります。
- メトリクス
- ログ
- トレース
この記事では、この中の一つ「ログ」について、Sentryがどう機能を提供しているかについて解説します。
構造化ログについて
アプリケーションからログを送信すれば、Sentryのダッシュボード内で表示したり、検索や関連するエラーとともに表示できます。文字列のログメッセージだけでなく、構造化されたデータ(注文情報やユーザの属性など)を送信することで、クエリに役立てたり、デバッグしやすくなります。
セットアップについて
ログ機能を有効にするのはとても簡単です。以下はJavaScript SDKにおける例です。
Sentry.init({
dsn: "https://YOURS.ingest.us.sentry.io/99999",
// 以下でログを有効化
enableLogs: true,
});
Pythonは以下のようになります。言語によってスネークケース、キャメルケースなどの違いはありますが、 enable_logs を有効にすればログ機能が使えるようになります。
sentry_sdk.init(
dsn="https://YOURS.ingest.us.sentry.io/99999",
enable_logs=True,
)
各SDK、プラットフォームにおける有効についてはSentry Docs | Application Performance Monitoring & Error Tracking Softwareをご覧ください。
ログ機能の使い方
例えばJavaScript SDKの場合は、以下のように書くとconsole.logなどをラップして動作するようになります。
Sentry.init({
dsn: "https://YOURS.ingest.us.sentry.io/99999",
integrations: [
// console.log / console.warn / console.error が Sentryに送られます
Sentry.consoleLoggingIntegration({ levels: ["log", "warn", "error"] }),
],
});
この他、 Sentry.logger が利用できます。
Sentry.logger.error(
Sentry.logger.fmt`Uh oh, something broke, here's the error: '${error}'`
);
Sentry.logger.info(
Sentry.logger.fmt`'${user.username}' added '${product.name}' to cart.`
);
Sentry.logger.trace("Starting database connection", { database: "users" });
Sentry.logger.debug("Cache miss for user", { userId: 123 });
Sentry.logger.info("Updated profile", { profileId: 345 });
Sentry.logger.warn("Rate limit reached for endpoint", {
endpoint: "/api/results/",
isEnterprise: false,
});
Sentry.logger.error("Failed to process payment", {
orderId: "order_123",
amount: 99.99,
});
Sentry.logger.fatal("Database connection pool exhausted", {
database: "users",
activeConnections: 100,
});
スコープを利用したログも可能です。
Sentry.getGlobalScope().setAttributes({
is_admin: true,
auth_provider: "sentry",
});
Sentry.withScope((scope) => {
scope.setAttribute("step", "authentication");
// スコープ属性 `is_admin`、`auth_provider` および `step` が追加されます
Sentry.logger.info(`user ${user.id} logged in`, { activeSince: 100 });
Sentry.logger.info(`updated ${user.id} last activity`);
});
// スコープ属性 `is_admin` および `auth_provider` が追加されます
Sentry.logger.warn("stale website version, reloading page");
外部ログライブラリとの連携
各種ログライブラリとも連携できます。JavaScript SDKでは、consola や winston 、Pino などとも連携できます。
import { consola } from "consola";
const sentryReporter = Sentry.createConsolaReporter();
/*
// 送信するログを限定する場合
const sentryReporter = Sentry.createConsolaReporter({
levels: ["error", "warn"],
});
*/
consola.addReporter(sentryReporter);
送信前処理
送信前にログをフィルタリングしたり、値を加工する際には beforeSendLog オプションが利用できます。
Sentry.init({
dsn: "https://YOURS.ingest.us.sentry.io/99999",
enableLogs: true,
beforeSendLog: (log) => {
if (log.level === "info") {
return null; // 送信しない
}
return log;
},
});
log オブジェクトには以下のキーがあります。
- level
文字列。trace/debug/info/warn/error/fatalのいずれか - message
文字列。ログに記録されるメッセージ - timestamp
数値。ログのタイムスタンプ - attributes
JSONオブジェクト。ログの各種属性
メッセージでテンプレートを使う
ログメッセージでテンプレートを使うことで、パラメータをログ属性として追加できます。
const user = "John";
const product = "Product 1";
Sentry.logger.info(
Sentry.logger.fmt`'${user}' added '${product}' to cart.`,
);
こうすることで、検索やデバッグ時に役立てられます。
まとめ
今回はSentryのログ機能について解説しました。適切なログを残しておくことは、迅速なデバッグを可能にします。また、構造化されたログを残すことで、検索やフィルタリングに役立てられます。普段の開発時から利用すれば、実運用時の問題解決にも役立てられるはずです。
ぜひ、Sentryのオブザーバビリティをお試しください!