Instana Node.js API
高度なモニタリング設定、カスタムトレース、または特定の統合を行うために、すべての Instana Node.js Tracer パッケージで、 Instana Node.js API をご利用いただけます。
Instana Node.js コレクターの初期化
インストールページで説明されているように、の主なエクスポートは、 Instana Node.js@instana/collector コレクターを初期化する関数です。 つまり、 require または importを使用してモジュールをロードすると、他のモジュールを要求またはインポートする前に、アプリケーション・コードによって呼び出す必要がある関数が返されます。 以下のセクションでは、 CommonJS モジュールシステムまたは ECMAScript モジュールシステムのいずれかを使用する Node.js アプリケーションについて、これについてさらに詳しく説明します。
CommonJS
@instana/collector によってエクスポートされた初期化関数を呼び出す必要があるのは 1 回だけですが、 Node.js アプリケーションの先頭、他の require ステートメントの前、および他のコードの実行前に呼び出す必要があります。
require('@instana/collector')();
初期化関数はそれ自体への参照を返します。これは、Instana Node.js コレクターによって提供される他のエクスポートにアクセスする場合に関係します。 すなわち、次の 2 つのスニペットは同じです。
const instana = require('@instana/collector')();
これは、次のように指定したことと同じです。
const instana = require('@instana/collector');
instana();
初期化関数は、1 つのオプション・パラメーターである構成オブジェクトを受け入れます。
const instana = require('@instana/collector')({
// ... configuration object, see configuration documentation
});
設定オブジェクトの詳細については、設定ページを参照してください。
Instana Node.js コレクター のインストールおよび初期設定に関する詳細については、「 Node.js コレクターのインストール」および 「コレクターの統合の確認」 を参照してください。
ESCMAScriptモジュール
ECMAScriptモジュールシステムを使用する Node.js アプリケーションでは、 Node.js のロードフラグを使用して、 Instana の Node.js コレクターを初期化してください。
ECMAScriptモジュールベースの Node.js アプリケーションで Instana Node.js SDKを使用したい場合は、次のようにして Instana API への参照を取得できます:
import instana from '@instana/collector';
エクスプレス・アプリケーションで現在のスパンを取得するには、次の例のようにコマンドを実行する:
import instana from '@instana/collector';
...
const app = express();
app.get('/', (req) => {
const span = instana.currentSpan();
console.log(span);
console.log(span.getTraceId());
})
起動時に指定された --importNode.js ロードフラグによってコレクタが初期化されるため、 Instana Node.js コレクタを再度初期化する必要はありません。
複数の Instana コレクターパッケージの使用
Kubernetes 環境では、複数の Instana コレクターが実行されている場合があります。
Kubernetes
Instana の AutoTrace Webhookを使用すると、 Node.js コレクターが自動的にディレクトリにインストールされます /opt/instana/instrumentation/nodejs/node_modules/@instana/collector 。
Kubernetes ベースの Node.js アプリケーションで Instana ( Node.js )SDKを使用する場合は、プロジェクトにを直接の依存関係として @instana/collector インストールすることをお勧めします。
const instana = require('@instana/collector')();
Instana へのアクセス API
ほとんどのアプリケーションでは、監視を行うために Instana コレクターを初期化するだけで十分です。 ただし、場合によっては、コレクターの初期化だけでなく、 Instana ( API )のその他の機能や部分を利用する必要が生じることもあります。 このようなケースには、高度なモニタリング設定、カスタムトレース、または特定の統合を必要とするシナリオが含まれます。
// At the start of your main module/application entry point, the function
// returned by require('@instana/collector') needs to be called to initialize
// the Instana Node.js collector. This needs to happen before anything else is
// required or imported.
const instana = require('@instana/collector')();
...
// Use the instana reference acquired by the require statement to access its
// API, for example:
instana.setLogger(...);
// or:
instana.currentSpan();
// or:
instana.opentracing.createTracer();
// ...
@instana/collector を参照する必要がある場合でも、 を @instana/collector 再度初期化する必要はありません。 アプリケーションのメインモジュールおよびアプリケーションのエントリポイントにあるファイルを除き、すべてのファイルで const instana = require('@instana/collector')(); の代わりに const instana = require('@instana/collector'); を使用できます。トレース状況の確認
トレースが有効になっているかどうかを確認するには、トレースの状況を検査する instana.isTracing() メソッドを使用できます。 この方法は、トレース状況に基づいてコードを条件付きで実行する必要があるシナリオで使用できます。 ただし、 Instana ではトレースが自動的に処理されるため、ほとんどの場合、トレースが有効になっているかどうかを確認する必要はありません。 この方法は、デバッグに使用することも、トレースを明示的に制御する必要がある複雑な環境で使用することもできます。
const instana = require('@instana/collector')();
if (instana.isTracing()) {
console.log('Tracing is enabled.');
} else {
console.log('Tracing is disabled.');
}
初期化後のロガーの設定
を使用して instana.setLogger(logger) 、デフォルトのpinoロガーではなく、カスタム @instana/collector ロガーを に指定します。
前述の通り、他のパッケージをrequireまたはimportする前に、直ちに初期化関数( Instana によって返されるもの require('@instana/collector'))を呼び出す必要があります。そうしないと、の自動トレース機能が部分的にしか動作しなくなります。 特に、ロギング・パッケージ (例えば、bunyan、pino、または winston) を要求する前に、Instana を初期化する必要があります。 Instana を初期化する前にロギング・パッケージを要求すると、Instana にログ・メッセージは表示されません。
一方、独自のロガーを Node.js コレクターに渡して、そのログ・メッセージの形式が残りのアプリケーションのログ・メッセージと同じになり、同じログ・ファイル/宛先に書き込まれるようにすることが必要な場合もあります。 ロガーをコレクターの初期化関数に渡す場合は、Instana を初期化する前にそのロギング・パッケージを要求する必要があります。 この循環依存関係を解決するために、@instana/collector は、最初にカスタム・ロガーなしで Instana を初期化してから、後でロガーを設定するための関数 setLogger を提供します。
具体的な例を示すために、以下はサポートされていません。
// WRONG
const instana = require('@instana/collector');
// The bunyan package will not be instrumented by Instana, because it is
// required *before* Instana has been initialized.
const bunyan = require('bunyan');
const logger = bunyan.createLogger(...);
// Now Instana is initialized, after the logging package has already been
// required. This is too late!
const instana = instana(); // TOO LATE!
instana.setLogger(logger);
代わりに、最初にロガーなしで Instana を初期化してから、他のものを要求します。 次に、後でロガーが必要になり、初期化されたときに、Instana が使用するロガーを設定します。
// Correct: Call the initialization function immediately.
// (Pay attention to the extra pair of parantheses at the end of the line.)
const instana = require('@instana/collector')();
// Require and initialize your logging package.
const bunyan = require('bunyan');
// Create your logger(s).
const logger = bunyan.createLogger(...);
// Set the logger Instana should use.
instana.setLogger(logger);
Instana のログ出力の最初の数行(初期化処理中)は、 Instana のデフォルトの pino ロガーによって記録されますが、その instana.setLogger(logger) 呼び出し以降のすべての内容は、ユーザーが設定したロガーによって記録されます。 さらに、アプリケーションのログ出力が Instana のダッシュボードの「ログ・メッセージ」タブに正しく表示されます (表示されるログ呼び出しは、重大度が「WARN」以上のもののみです)。
Bunyan または Pino ロガーを setLogger に渡すと、Node.js コレクターは、同じログ・レベルとターゲット・ストリームを使用して所定のロガーの子を作成します。 他のロギング・モジュールも、ログ・レベル debug、info、warn、および error の機能を提供する限り、サポートされます。 この場合 Node.js コレクターは子ロガーを作成するのではなく、指定のロガーをそのまま使用します。
@instana/collector に提供するロガーで必要なログ・レベルを設定するのはお客様の責任であることに注意してください。 @instana/collector から予期しないデバッグ・ログが表示される場合、レベルが info または warn に設定されているロガーを必ず渡してください。
現在アクティブなスパンへのアクセス
Instana の自動トレース機能は、 対応ライブラリに関してはすべてを自動的に処理するため、ユーザー側で何かを行う必要はありません。
しかし、アプリケーション・コードに付与される権限は、コレクターの内部状態への限定された読み取り専用アクセス権限です。 この目的のために、 instana.currentSpan()を使用して、現在アクティブなスパンのハンドルを獲得することができます。 現在アクティブなスパンがない場合、このメソッドはダミー・ハンドルを戻します。 このメソッドによって戻されるスパン・ハンドルは、以下のメソッドを提供します。
span.getTraceId(): スパンのトレース ID を返します。 (v1.62.0 以降)
span.getSpanId(): スパンのスパン ID を返します。 (v1.62.0 以降)
span.getParentSpanId(): スパンの親スパン ID を返します。 (v1.62.0 以降)
span.getName(): スパンの名前を返します。 (v1.62.0 以降)
span.isEntrySpan(): スパンがエントリー・スパン (サーバー・スパン) かどうかを判別します。 (v1.62.0 以降)
span.isExitSpan(): スパンがエグジット・スパン (クライアント・スパン) かどうかを判別します。 (v1.62.0 以降)
span.isIntermediateSpan(): スパンが中間スパン (ローカル・スパン) であるかどうかを判別します。 (v1.62.0 以降)
span.getTimestamp(): スパン開始のタイム・スタンプを返します (v1.62.0 以降)。
span.getDuration(): スパンの期間を返します。 スパンがまだ完了していない場合、このメソッドは 0 を返します。 instana.currentSpan() が現在アクティブなスパン (当然、完了していない) を返すため、これはほとんどの場合に当てはまることに注意してください。 これは、 span.disableAutoEnd() および span.end() が使用されている場合にのみ、0 より大きい期間を返します (以下を参照)。 (v1.62.0 以降)
span.annotate(path, value): スパンに注釈 (タグまたはカスタム・タグとも呼ばれます) を追加します。 path は、ドット区切りの文字列または一連の文字列として指定できます。 すなわち、次の 2 つの呼び出しは同じです。
span.annotate('sdk.custom.tags.myTag', 'My Value')、およびspan.annotate(['sdk', 'custom', 'tags', 'myTag'], 'My Value').span.annotate(['sdk', 'custom', 'tags', 'service'], 'dummy service').
カスタム・タグの前には必ず sdk.custom.tags が付いていることに注意してください。 また、annotate を使用して、HTTP パス・テンプレート (例: span.annotate('http.path_tpl', '/user/{id}/details')) のような標準タグをオーバーライドすることもできますが、Instana の自動トレースに干渉する妥当性がない限り、推奨されません。 (v1.97.1 以降)
span.markAsErroneous(message, [customErrorMessagePath]): スパン・エラー・カウントを 1 に設定することにより、スパンにエラーのマークを付ける。 メッセージ引数は、スパンが誤っていると見なされる理由を説明します。 このメソッドが引数なしで呼び出されると、デフォルトのエラー・メッセージが自動的に設定されます。 エラーメッセージのカスタムパスを指定する(customErrorMessagePath)はオプションであるためNode.jsトレーサーはパスを自動的に処理します。
例:
- スパンにエラーのマークを付ける:
const instana = require('@instana/collector')();
...
const span = instana.currentSpan();
// Mark the current span as erroneous with the default error message.
span.markAsErroneous();
// Mark the current span as erroneous with a custom error message.
span.markAsErroneous('Custom error message');
- HTTP のスパンを、カスタムパスを使用してエラーとしてマークする:
const instana = require('@instana/collector')();
app.get('/example', (req, res) => {
...
const span = instana.currentSpan();
// Mark HTTP span as erroneous with a Custom Error Message and Custom Path
span.markAsErroneous('Custom error message', 'http.error');
...
});
span.markAsNonErroneous([customErrorMessagePath]): スパンをエラーなしとしてマークします。 このメソッドは、スパンが以前にエラーとしてマークされていた場合に、自動トレース・インスツルメンテーションによって、または span.markAsErroneous メソッドを呼び出すことによって、スパンをエラーなしにするのに役立ちます。 span.markAsErroneous メソッドの呼び出し時に customErrorMessagePath パラメーターを使用した場合は、 span.markAsNonErroneous メソッドに同じパスを指定します。 そうでない場合は、 customErrorMessagePath パラメーターを省略できます。 ( v2.25.2以降)
span.getErrorCount(): 現在アクティブなスパンに関連付けられている要求の処理中に発生したエラーの数を返します。 このメソッドは、スパンがエラーとしてマークされている場合は 1 を返し、それ以外の場合は 0 を返します。 1 より大きいエラー件数は、現行スパンがバッチ・スパンである場合にのみ発生する可能性があります。 (v1.62.0 以降)
span.disableAutoEnd(): 次のセクションを参照してください。 (v1.55.1 以降)
span.end(errorCount): 次のセクションを参照してください。 (v1.55.1 以降)
手動でのスパンの終了 (メッセージ・ブローカー項目)
先ほども触れたように、 Instana の自動トレース機能は、 対応ライブラリについてはすべて自動的に処理してくれるため、ユーザーが手動で介入する必要はありません。 ただし、このルールには例外があります。それは、メッセージブローカー( Kafka、 RabbitMQ, NATS、NATS streaming、 Google Cloud PubSub )からメッセージを受信したことをきっかけとしてトリガーされたトレース操作です。 メッセージ・ブローカーからメッセージをコンシュームした場合に応答という概念がないため、特定のメッセージによってトリガーされるすべての操作が終了したときに Instana Node.js コレクターに知らせるイベントがありません (一方、着信 HTTP 要求は、常に応答が関連付けられ、トランザクションの終わりを示します)。
プロセスは、新規メッセージを受信すると、エントリー・スパンを開始します。 Instana のトレース機能には、このスパンが終了したことを示す何らかのイベントが必要です。 その他の呼び出しは、エントリー・スパンの開始から終了までの間にトリガーされた場合にのみ、同じトレースに割り当てられます。 したがって、着信メッセージの処理が完了したときにアプリケーション・コードは Instana に知らせる必要があります。 この目的のために、現在アクティブなスパン用のハンドル( instana.currentSpan() 取得方法については「 現在アクティブなスパンへのアクセス 」を参照)を使用できます。 このハンドルは、このユース・ケースに関連する以下の 2 つのメソッドを提供します。
span.disableAutoEnd(): スパンの自動終了を無効にし、後で span.end() を呼び出して手動で終了するスパンというマークをこのスパンに付けます。
span.end(errorCount): 先に span.disableAutoEnd() が呼び出されていたスパンを終了します。 errorCount 引数はオプションです。 メッセージの処理中にエラーが発生した場合は、1 を渡します。 何も渡されない場合、errorCount はデフォルトで 0 に設定されます。
これが RabbitMQ の場合にどのようになるかを次の例に示します。
channel.consume(queueName, function(msg) {
var span = instana.currentSpan();
span.disableAutoEnd();
// The setTimeout is a placeholder for any number of asynchronous operations
// that are executed when processing this particular message. It could also be
// database access calls or outgoing HTTP calls or really anything else.
setTimeout(function() {
// call span.end when processing of the incoming message has finshed. Make
// sure to also call in case an error happens while processing the message.
span.end();
}, 5000);
});
span.disableAutoEnd() を呼び出しても、それに対してspan.end()を呼び出さないと、スパンがバックエンドに送信されないことに注意してください。
また、 Kafka、 RabbitMQ 、および NATS などのメッセージ・ブローカーの場合、メッセージ処理機能で span.disableAutoEnd() を同期的に呼び出さないと、スパンは終了し、メッセージ処理機能が戻った後に自動的に 即時 伝送されることに注意してください。 これにより、そのトレースは中断されます。つまり、そのメッセージの処理中に実行された操作 (DB アクセス、発信 HTTP 呼び出し、他のメッセージの送信) は Instana で呼び出しとして出ることはありません。
メッセージ・ブローカーへの 送信/公開 メッセージの場合は、これを行う必要はありません。
アクティブなエントリ・スパンが存在しない場合にトレースを有効にする
Instana のCollectorバージョン 4.0 以降では、エントリ・スパンがなくても、エクジット・スパンをキャプチャすることができます。 この機能を有効にするには、環境 INSTANA_ALLOW_ROOT_EXIT_SPAN 変数を設定するか、tracerの設定を通じて設定してください。 この機能の設定方法の詳細については、「エントリースパンなしでルート終了スパンを許可する」を参照のこと。
Instana 以前のコレクター( 4.0 )では、 Instana ( Node.js )コレクターは、アクティブなエントリー・スパンが存在する場合にのみ、終了スパンまたは中間スパンをキャプチャします。 詳細については、アクティブなエントリースパンが存在しない場合、トレースは非アクティブになるを参照のこと。
SDK を使用したスパンの手動作成
コレクターは、すぐにトレースできるように、広く使用されているAPIを自動的に計測します。 例:
カスタム・ライブラリまたはフレームワーク:SDKを使用して、自動的にインスツルメンテーションされないアプリケーションの領域のスパンをキャプチャし、他の方法では見逃される洞察を提供することができます。
中間スパン:スパンを作成することで、コード内の重要なセクションを明確に区分けし、特定の操作をより深くトレースすることができます。
内部でトリガーされた作業:
setInterval、'setTimeout、または同様のメソッドによってトリガーされるスケジュールされたジョブのように)それ自体で作業を開始するアプリケーションの場合、SDKを使用して、外部ソースからの着信要求がなくても、このアクティビティのトレースを有効にすることができます。
SDK で作成されたスパンは、Instana の自動トレース機能とシームレスに統合されます。
用語
SDK は、エントリー・スパン、中間スパン、およびエグジット・スパンを作成する機能を提供します。 要約すると、以下のとおりです。
- エントリー・スパンは、モニター中のアプリケーション への 呼び出しを表します。 これらの呼び出しは、アプリケーションが他のサービスから受け取るHTTP リクエスト、あるいはアプリケーションがキューから取得するメッセージである可能性があります。 (言うまでもなく HTTP 要求は既に自動トレースの対象です。) 一般に、エントリー・スパンは、Node.js アプリケーション内で処理をトリガーする主体を表します。 トレースは常に、エントリースパン(自動計測またはSDKを通じて作成されたもの)から開始する必要がある。 Node.js のトレーサーは非アクティブのままとなり、アクティブなエントリ・スパンが終了しない限り、中間スパンや終了スパンはキャプチャされません。 詳細については、アクティブなエントリースパンがない場合、トレースは非アクティブのセクションを参照のこと。
- エグジット・スパンは、アプリケーションが行う呼び出しを表します。 これらは、アプリケーションが 作成する (および他のサービスによって応答される) またはデータベース呼び出しの HTTP 要求である可能性があります。 (この場合も、発信 HTTP 要求と多くの一般的なデータベースは、既に自動インスツルメンテーションの対象になっています。)
- 中間スパンとは、モニター対象のアプリケーション内部で発生するものです。つまり、エントリー・スパンとエグジット・スパンが行うように、アプリケーションがプロセスに入ったり、プロセスから出たりすることはありません。 また、自動装備では提供されない追加属性 ( タグと呼ばれる) を提供したい場合は、中間スパンを使用して、自動的に作成されたスパンをラップすることもできます。
用語の詳細、特に、 スパン が Instana UI に表示される 呼び出し とどのように関連するかについては、 トレース資料を参照してください。
また、SDK を使用してカスタムトレースの実装を始める前に、 トレースのベストプラクティスに関するセクションも一読する価値があります。
ついに、 Instana Node.js SDK の使い方を学ぶのに役立つ、ローカルで起動して確認できるデモアプリが登場しました: https://github.com/instana/instana-nodejs-demos/tree/master/sdk。
コールバックベースの API、Promiseベースの API、およびAsync API
SDK は、3 つの異なるタイプの API を提供します。1 つはコールバック・ベース (instana.sdk.callback)、1 つは promise ベース (instana.sdk.promise)、もう 1 つは async/await スタイル (instana.sdk.async) を使用するコード用です。 どちらが使用されるかは、純粋に味の問題です。 基本的に、3 つの API はすべて、スパンの開始とスパンの完了のためのさまざまな方法を提供します。 スパンが表す作業を行う前に、スパンを直接開始し、作業が終了したら、スパンを完了する必要があります。
Callback API を使用する場合、新しいスパンを開始するたびにコールバックを渡し、そのコールバック内部 (またはそのコールバックから過渡的にトリガーされる非同期操作のコールバック) でそのスパンに関連付けられているすべての作業を実行する必要があります。 以下に例を示します。
instana.sdk.callback.startEntrySpan('my-custom-span', () => {
// The actual work needs to happen inside this callback (or in the callback
// of any asynchronous operation transitively triggered from this callback).
...
doSomethingAsynchronous((err, result) => {
if (err) {
instana.sdk.callback.completeEntrySpan(err);
logger.error(err);
return;
}
instana.sdk.callback.completeEntrySpan();
logger.info('Yay! 🎉', result);
});
});
startXxxSpan に提供されるコールバックは、引数なしで即時かつ同期的に呼び出されることに注意してください。 その他の非同期操作は、そのコールバック内でトリガーできます。
Promise API を使用すると、新しいスパンを開始するすべてのメソッドがプロミスを返します。 そのスパンに関連付けられたすべての作業は、そのプロミス・チェーン (つまり、startXxxSpan によって返されるプロミスの then、またはプロミス・チェーンのさらに下の then ハンドラー) で行われる必要があります。 以下に例を示します。
instana.sdk.promise.startEntrySpan('my-custom-span').then(() => {
// The actual work needs to happen inside the promise chain, that is, either
// here or in any `then` handler further down the promise chain.
return anotherPromise();
}).then(result => {
instana.sdk.promise.completeEntrySpan();
logger.info('Yay! 🎉', result);
}).catch(err => {
instana.sdk.promise.completeEntrySpan(err);
logger.error(err);
});
startXxxSpan によって返されるプロミスは拒否されることなく、値なしで即時に解決されることに注意してください。 その他の非同期操作は、その then ハンドラー内でトリガーできます。
async/await スタイルのコードの場合、SDK は instana.sdk.async を提供します (バージョン 1.81.0 以降)。
await instana.sdk.async.startExitSpan('my-custom-span');
try {
await someOtherAsynchronousOperation();
instana.sdk.async.completeExitSpan();
} catch (err) {
instana.sdk.async.completeExitSpan(err);
logger.error(err);
}
async/await コードは Node.js ランタイムでプロミスを介して処理されるため、内部で instana.sdk.async は instana.sdk.promise の単なる別名です。
completeXxxSpan メソッドは、3 つのすべての API フレーバーで同じです。
上記の例だけでは物足りないという方は、 Node.js SDKの機能を余すところなく紹介している、実際に動作するデモアプリをぜひご覧ください: https://github.com/instana/instana-nodejs-demos/tree/master/sdk。
API メソッド
以下の共通パラメーター は、SDK のメソッドで受け入れられます。
name: スパン名。 新しいスパンを開始する場合、このパラメーターは必須です。 短く分かりやすい文字列でなければなりません。tags: スパンの追加メタデータのオプション JS オブジェクト。 スパンの開始時または完了時、あるいはその両方でタグを指定できます。 スパンの開始時および完了時にタグを指定すると、両方のオブジェクトがマージされます。 タグは Instana UI に表示されます。 作成するスパンには、任意にラージ・オブジェクトを追加しないようにする必要があります。 短いキーと値のペアを使用する必要があります。 スパンが大きすぎると、Instana エージェントに送信されるのではなく、スパンのバッチが除去される可能性があります。error: 現在のスパンに関連付けられた作業の実行中にエラーが発生した場合、このエラーが完了時にスパンに付加できます。traceId: これはエントリー・スパンにのみ関係し、エントリー・スパンを、既に別のプロセスで開始されている既存のトレースの一部にするために使用されます。traceIdを指定する場合は、parentSpanIdも指定する必要があります。parentSpanId: これは、既に別のプロセスで開始されている既存のトレースの一部であるエントリー・スパンにのみ関係します。 このエントリー・スパンをトリガーしたエグジット・スパンを参照するために使用されます。parentSpanIdを指定する場合は、traceIdも指定する必要があります。
以下のメソッド は、3 つのすべての API で提供されます。
instana.sdk.callback.startEntrySpan(name [, tags[, traceId, parentSpanId]], callback),instana.sdk.{promise|async}.startEntrySpan(name [, tags[, traceId, parentSpanId]]): エントリのスパンを開始します。 スパンのnameを指定する必要があります。 オプションでtagsオブジェクトを提供できます。traceIdとparentSpanIdもオプションですが、両方の ID を指定するか、どちらの ID も指定しないかのどちらかにする必要があります。instana.sdk.callback.completeEntrySpan([error, tags]),instana.sdk.{promise|async}.completeEntrySpan([error, tags]): エントリ・スパンを終了します。 エラーと追加のタグを指定できます。 追加のタグを指定するものの、エラーを指定しない場合は、最初の引数としてnullを渡します。instana.sdk.callback.startIntermediateSpan(name[, tags], callback),instana.sdk.{promise|async}.startIntermediateSpan(name[, tags]): 中間スパンを開始します。 span 要素nameに対して を指定する必要があります。また、必要に応じて オブジェクトtagsを指定することもできます。 関数呼び出しは、開始されたスパンを戻します。instana.sdk.callback.completeIntermediateSpan([error, tags, span]),instana.sdk.{promise|async}.completeIntermediateSpan([error, tags, span]): 中間スパンを完了します。 エラー、追加のタグ、および完了するスパンを指定できます。 エラーを出さずに追加のタグを指定したい場合は、最初の引数として をnull渡してください。instana.sdk.callback.startExitSpan(name[, tags], callback),instana.sdk.{promise|async}.startExitSpan(name[, tags]): 終了スパンを開始します。 スパンのnameを指定する必要があります。オプションでtagsオブジェクトを指定できます。instana.sdk.callback.completeExitSpan([error, tags]),instana.sdk.{promise|async}.completeExitSpan([error, tags]): 終了スパンを終了します。 エラーと追加のタグを指定できます。 追加のタグを指定するものの、エラーを指定しない場合は、最初の引数としてnullを渡します。instana.sdk.callback.bindEmitter(emitter),instana.sdk.{promise|async}.bindEmitter(emitter): 以下の通りです。
startXxxSpan メソッドで開始されたスパンは、対応する completeXxxSpan が呼び出されると Instana にのみ送信されることに注意してください。 また、ネストされたspan要素については、呼び出しの順序を正しくする必要があります。
また、Promise API を使用してスパンをネストする場合も、注意が必要です。 以下は正しい指定です。
instana.sdk.promise.startEntrySpan('custom-entry')
// any number of other promises/async operations
.then(() => {
...
})
.then(() => {
return instana.sdk.promise.startExitSpan('custom-exit')
// any number of other promises/async operations associated with the exit span
.then(() => {
...
})
.then(() => {
// Important: The exit span needs to be completed in the promise chain
// started with startExitSpan, not in the outer promise chain started
// with startEntrySpan.
instana.sdk.promise.completeExitSpan();
});
})
.then(() => {
instana.sdk.promise.completeEntrySpan();
logger.info('Yay! 🎉');
});
中間スパンについては、以下の有効な例を参照してください。
await instana.sdk.async.startIntermediateSpan('intermediate-span-name')
// trigger an internal request
await request(`http://127.0.0.1:${port}`)
instana.sdk.async.completeIntermediateSpan();
// This example demonstrates how to start two overlaping intermediate spans.
const span1 = await instana.sdk.async.startIntermediateSpan('intermediate-span-name-1')
await request(`http://127.0.0.1:${port}`)
const span2 = await instana.sdk.async.startIntermediateSpan('intermediate-span-name-2')
await request(`http://127.0.0.1:${port}`)
// Pass "span1" as third argument to signalise which span to complete.
instana.sdk.async.completeIntermediateSpan(null, null, span1);
await request(`http://127.0.0.1:${port}`)
instana.sdk.async.completeIntermediateSpan(null, null, span2);
この時点で、SDK の API がこのように設計されている理由を疑問に思うかもしれません。特に、コールバックを受け入れるかプロミスを返す startXxxSpan メソッドでの仕様が煩わしく思えるかもしれません。 問題は、トレース中に非同期コンテキストを保持する必要があることです。 Node.js は単一スレッドであり、コールバックを使用して非同期操作を実行するため、Node.js コレクターは、どの操作がどのスパンに属するかを判別する方法が必要です。トレースされたアクションをコールバックまたはプロミスでラップすると、それが可能になります。
イベント・エミッターの処理
カスタム SDK スパンに関連付けられている作業に イベント・エミッター が含まれており、スパン内で実行されているコードが出力されたイベントを傾聴する場合は、イベント・エミッターを バインド する必要があります。そうしないと、トレース・コードが予期したとおりに動作しません。 以下に、その方法を示します。
instana.sdk.callback.startEntrySpan('custom-span', () => {
const emitter = ... // some event emitter
instana.sdk.callback.bindEmitter(emitter);
...
emitter.on('some-event', () => {
instana.sdk.callback.completeEntrySpan();
logger.info('Done! 🎉');
});
});
アクティブなエントリ・スパンが存在しない場合、トレース機能は無効になります
原則として、Instana トレーサーは、アクティブなエントリー・スパンがある場合にのみ、エグジット・スパンまたは中間スパンをキャプチャーします。 これは、ビジネス関連トランザクションの処理とは関係のないノイズをキャプチャーしないようにするための重要な安全機能です。 ただし、この安全機能が妨げとなることがあるエッジ・ケースがあります。 その例としては、 Instana の自動インスツルメンテーションではサポートされていないメカニズムによってトリガーされる処理などが挙げられます:
- (まだ) サポートされていないメッセージング・ライブラリーからの着信メッセージ
- サポートされていないプロトコルを介した要求 (自動インスツルメンテーションでサポートされていないロー TCP メッセージや WebSocket 通信など)
- 外部からトリガーされたのではなく、
setTimeout、setInterval、サポートされていない Node.js スケジューリング・ライブラリーなどを使用してプロセス自体でトリガーされたスケジュール済みジョブを実行するアプリケーション
エントリー・スパンがないと、Instana の Node.js トレーサーでは、このコンテキストで行われる呼び出しのその他の中間スパンやエグジット・スパンのキャプチャーも一切行われません。 つまり、次のようになります。
- サポートされているライブラリを介して、 HTTP への送信リクエスト、データベース呼び出し、または出口スパンが生成されるその他の処理がトリガーされた場合でも、アクティブな入口スパンが存在しないときは、その出口スパンはキャプチャされません。
- Instana Node.js SDK を使用して中間スパンまたはエグジット・スパンを開始しても、アクティブなエントリー・スパンがなければ、SDK はそのスパンの開始を拒否します。 これに関する警告がログに記録されます。
しかし、現在ではこのような状況に対する解決策が用意されている。 Instana のコレクター( 4.0 以降)では、エントリスパンが存在しない場合でも、エクシッツパンをキャプチャすることができます。 この機能を有効にするには、「Allow root exit span without entry span」の説明を参照のこと。 Instana コレクターのバージョン 4.0 より前のバージョンでは、タスクの開始時に手動でエントリースパンを開始し、タスクが完了した時点でそれを終了させる必要があります。 アクティブなエントリースパンが存在することで、すべてのエグジットスパンと中間スパンが確実にキャプチャされる。
また、使用しているトリガーのタイプに対するすぐに使用可能なサポートを実装するために、 フィーチャー要求を作成 することもできます。
非同期コンテキストの手動復元
Instana 内部的には、非同期コンテキストを維持するために async_hooks に依存しています。 これは、手操作による介入なしに自動的かつ透過的に機能します。 ただし、async_hooks の継続性を中断して非同期コンテキストを失う可能性があるライブラリーとコード・パターンがあります。 そのうちのいくつかは、この問題一覧に記載されています。 このようなモジュールを使用すると、トレースが不完全になり、呼び出しが欠落する可能性があります。
Instana の Node.js SDK には、これを修正するための API が用意されています。 しかし、この API を使用する必要はほとんどありません。 これを使用する必要があるのは、欠落している呼び出しの原因となっているコード行とその理由が正確にわかっている場合のみです。
instana.sdk.getAsyncContext(): 現在アクティブな非同期コンテキストを返します。 これは、非同期継続を中断するコードを呼び出す前に呼び出します。 (v1.100.0 以降)instana.sdk.runInAsyncContext(context, callback): 指定された非同期コンテキストで所定のcallbackを実行します。contextオブジェクトは、instana.sdk.getAsyncContext()を呼び出すことによって取得されていなければなりません。 そのコンテキストで実行する予定のすべてのコードをcallbackにラップします。 (v1.100.0 以降)instana.sdk.runPromiseInAsyncContext(context, createPromiseFn): 指定された非同期コンテキストでプロミスを実行します。contextオブジェクトは、instana.sdk.getAsyncContext()を呼び出すことによって取得されていなければなりません。 関数createPromiseFnは、そのコンテキストで実行するプロミスを返すことが予期されています。 (v1.100.0 以降)
使用法を示す runInAsyncContext のコード例は次のとおりです。
// ...
// 1. Fetch the currently active asynchronous context directly _before_ the
// asynchronous operation that breaks async_hooks continuity.
const activeContext = instana.sdk.getAsyncContext();
someLibrary.functionThatBreaksAsyncContinuity((error, result) => {
// 2. Restore the asynchronous context directly _after_ the asynchronous
// operation that breaks async_hooks/async_wrap continuity by calling
// instana.sdk.runInAsyncContext with the context object acquired
// earlier.
instana.sdk.runInAsyncContext(activeContext, () => {
// 3. Wrap all subsequent code in the callback given to instana.sdk.runInAsyncContext.
if (error) {
// ...
}
// ...
});
});
runPromiseInAsyncContext のコード例は次のとおりです。
// ...
// 1. Fetch the currently active asynchronous context directly _before_ the
// asynchronous operation that breaks async_hooks continuity.
const activeContext = instana.sdk.getAsyncContext();
someLibrary.functionThatBreaksAsyncContinuity((error, result) => {
// 2. Restore the asynchronous context directly _after_ the asynchronous
// operation that breaks async_hooks/async_wrap continuity by calling
// instana.sdk.runInAsyncContext with the context object acquired
// earlier.
return instana.sdk.runPromiseInAsyncContext(activeContext, () => {
/* a function that returns the promise you want to run */}
);
});
OpenTracing 統合
このパッケージは、OpenTracing API も実装します。 Instana を使用している Node.js で OpenTracing を利用するには、 自動トレースを無効にし、 Instana OpenTracing API の実装を使用する必要があります。 以下のプロジェクト例は、これを示しています。
// Always initialize the collector as the first module inside the application.
const instana = require('@instana/collector')({
tracing: {
automaticTracingEnabled: false
}
});
// instantiate the OpenTracing tracer:
const opentracing = require('opentracing');
// optionally use the opentracing provided singleton tracer wrapper
opentracing.initGlobalTracer(instana.opentracing.createTracer());
// retrieve the tracer instance from the opentracing tracer wrapper
const tracer = opentracing.globalTracer();
// start a new trace with an operation name
const span = tracer.startSpan('auth');
// mark operation as failed
span.setTag(opentracing.Tags.ERROR, true);
// finish the span and schedule it for transmission to instana
span.finish();
制限
- OpenTracing は Instana の自動トレースに組み込まれていません。 特に、OpenTracing API を使用して作成されたスパンは、自動トレース・インスツルメンテーションによって作成されたスパンと同じトレースの一部にはなりません。 自動作成されたスパンに 追加 スパンを追加する場合は、OpenTracing よりも SDK を優先する必要があります。 実際には、自動トレース (オプションで SDK スパンによって拡張される) または OpenTracing のいずれかを使用し、1 つのアプリケーションで両方を使用しないことをお勧めします。
- Instana Node.js コレクターは、OpenTracing バイナリー・キャリアをサポートしません。 この OpenTracing の実装では、OpenTracing バイナリー・キャリア・オブジェクトはサイレントに無視されます。
- OpenTracing バゲージ項目にも注意が必要です。 バゲージ項目は、ネットワーク境界を越えてキャリア・オブジェクトを介してトランスポートされるメタデータです。 さらに、このメタデータは子スパン (およびその子スパン ...) によって継承されます。. これにより、いくらかのオーバーヘッドが生じる可能性があります。 OpenTracing バゲージ API を完全に回避することをお勧めします。