Syntheticsモニタリングを使用すると、アプリを監視しテストできるので、エンドユーザーに影響が生じる前に問題に対処できます。そのフルパワーを活用するための5つのヒントを以下にご紹介します。
1. Syntheticモニターを選択
Syntheticsモニターは、ウェブサイトのパフォーマンスを測定し、読み込み時間、稼働時間、平均ダウンロードサイズの集計値をキャプチャする仮想ブラウザです。また、ダウンタイムインシデントと各ページリソースに関する詳細な統計情報にもアクセスできます。
モニターの対象と方法に応じて、7種類のSyntheticモニターから選択できます。たとえば、ステップモニターは、コードを記述せずにスクリプト化されたブラウザとして、本質的に機能するものを作成するための優れた方法です。Syntheticモニターの自動管理をお探しの場合は、当社のNerdGraph APIを使用すると、API呼び出しを通じてSyntheticモニターを作成、更新、削除できます。
Syntheticモニターを追加する
- モニターを追加するには、one.newrelic.com > Syntheticsの順に移動します。(EUベースのアカウントをお持ちの場合は、one.eu.newrelic.comに移動します。) Create monitorをクリックします。
モニタータイプを選択し、すべての必須フィールドに入力します。
タグの追加、期間の変更、または別のランタイムバージョンの選択ができます。pingおよび単純なブラウザモニターでは、検証文字列を追加できます。高度なオプションを使用して、次のタイプの応答検証の部分文字列モニタリングを有効にすることができます。
SSL検証(Pingとシンプルブラウザ用)。このオプションは、SSL証明書チェーンの有効性を検証します。次の構文を実行することによって複製することができます。
bash$openssl s_client -servername <var>{YOUR_HOSTNAME}</var> -connect <var>{YOUR_HOSTNAME</var>}:443 -CApath /etc/ssl/certs > /dev/nullHEADリクエストのバイパス(Pingモニター用)。このオプションは、デフォルトのHEADリクエストをスキップし、その代わりにpingチェックを含むGET動詞を使用します。HEADリクエストが失敗した場合、GETリクエストは常時発生します。
Redirect is Failure(Ping用)。
Redirect is Failure
が有効になっているときにリダイレクト結果が発生すると、Syntheticsモニターはリダイレクトにしたがって、結果のURLをチェックするのではなく、結果をエラーとして分類します。
モニターを実行するロケーションを選択します。誤検出を避けるために、少なくとも3つの場所を選択するようにしてください。つまり、少なくとも1つの場所が成功した結果を返す場合、エンドポイントは稼働しており、アラートのトリガーを回避できます。
モニターの種類に応じて、モニターの保存、検証、スクリプトの記述のいずれかを行うよう求められます。
結果を受け取ったら、概要ページで表示します。
2. Syntheticモニターの概要ページを表示する
概要ページには、Syntheticモニターのステータスに関する情報が表示されます。アラートをトリガーするアクティブなインシデントが作成された場合は、このモニターのクリティカルなアラートをクリックして新しいタブで開きます。また、クリックしてページ上部のすべてのモニターのアラートポリシーを管理すると、モニターのすべてのアラートポリシーにアクセスすることもできます。
3. アプリケーションのパフォーマンスの全体像を把握
アプリケーションのパフォーマンス結果を継続的に確認して、ウェブサービスが適切に機能し、期待どおりに動作し、エラーが発生しないようにする必要があります。Syntheticsモニタリングでは、選択した場所ごとにウェブアプリケーションで自動テストを実行することで確実にします。Syntheticsモニターは、ダウンタイムインスタンス(「違反」と呼びます)を記録し、各ページリソースの集計数、結果、および詳細な統計情報を収集します。
この情報の高レベルの情報を取得するには、モニターインデックスを使用して、モニターの
概要を表示したり、簡易モニターとスクリプト化されたモニターの概要を取得したりできます。これらのページにより、時間の経過に伴うアプリケーションのパフォーマンスに関するより深い洞察を得ることができます。
エクスプローラーでモニターを表示する
4. 個々のモニター結果を表示する
世界中のさまざまな地域からアクセスされるウェブアプリのパフォーマンスを確認する必要があります。結果ページには、開発から本番までのすべてがユーザー体験にいかに影響するかが表示されます。リストされているものを並べ替えて、問題のある領域や異常結果を特定できます。場所別にフィルタリングして、さまざまな場所からのモニターのパフォーマンスを比較してみてください。(以下の「ネットワークタイミング」グラフは、一定期間にわたるウェブページのパフォーマンスのスナップショットを示しています。)これを行うには、以下を実行します。
- one.newrelic.com > Syntheticsの順に移動します。
- モニタータブからモニターを選択します。
- モニターをクリックし、結果をクリックします。
結果から監視対象の各場所に対して最も遅いページロードの最新のビューが得られます。
5. 各リソースのロードタイムへの影響を把握する
Syntheticsリソースページには、ウェブサイトのさまざまなコンポーネント(CSS、JavaScript、画像、HTMLなど)が全体的な負荷にどのように影響しているかが表示されます。ランタイムに収集される詳細なメトリクスを掘り下げて調べ、サードパーティリソースによって費やされる時間に関するパフォーマンス情報を検出し、各リソースのHTTP応答コードを特定することができます。これを行うには、以下を実行します。
- one.newrelic.comへ移動します。Syntheticsをクリックします。
- モニタードロップダウンメニューから、モニターを選択します。
- モニターをクリックし、リソースをクリックします。
6. スクリプト化ブラウザテストを設定して開発する
スクリプト化ブラウザを使用して、Selenium JavaScript Webdriverバインディングで複雑な監視ワークフローを構築できます。たとえば、アプリケーションにログインして特定のリンクにナビゲートし、ページ要素がロードされてアサーションを追加するのを待機できます。これを行うには、以下を実行します。
- one.newrelic.com > Syntheticsの順に移動します。
- モニタータイプ(スクリプト化ブラウザなど)を選択します。
- モニターの名前と詳細(
sitename.com
のスクリプト化ブラウザなど)を入力します - モニターを実行する場所 (ムンバイ、ソウル、コロンバス、モントリオールなど) を選択します。
- ここからモニターを実行する頻度 (5分など) を選択します。
- パフォーマンス違反が発生した際にチームに送信するアラート通知を設定します。
- これでスクリプトを記述する準備ができました。(以下は、newrelic.comのパフォーマンスをテストし、特定の要素が読み込まれたことを確認するスクリプトの例です。)
/** * Script Name: scripted browser - next gen runtime * Author: New Relic * Version: 1.0 * Purpose: best practices example * Reference: https://docs.newrelic.com/docs/synthetics/synthetic-monitoring/scripting-monitors/synthetic-scripted-browser-reference-monitor-versions-chrome-100 */
// -------------------- CONSTANTSconst SCRIPT_NAME = "scripted browser - next gen runtime" // name to record in script logconst DEFAULT_TIMEOUT = 10000 // default is 10 seconds to locate page locconst PAGE_LOAD_TIMEOUT = 60000 // a negative value defaults to 180 secondsconst USER_AGENT = "default" // set the user agent for Chromeconst PROTOCOL = "https://" // set the protocolconst USERNAME = "" // username:const PASSWORD = "" // password@const DOMAIN = "newrelic.com" // your domainconst PATH = "" // /path/to/pageconst CHECK = "Correlate issues across your entire stack" // text to match on page
const AUTH = USERNAME + PASSWORDconst FULL_URL = PROTOCOL + AUTH + DOMAIN + PATH
// -------------------- CONFIGURATIONvar assert = require("assert")// script-wide timeout (ms) for functions: waitForAndFindElement and waitForPendingRequests// better to fail early if it is expected to take less time than the DEFAULT_TIMEOUT// in order to release the heavy worker thread on the minion for the next job$webDriver.manage().setTimeouts({pageLoad: DEFAULT_TIMEOUT}) // sets element load timeout$webDriver.manage().setTimeouts({pageLoad: PAGE_LOAD_TIMEOUT}) // sets page load timeout
// -------------------- VARIABLESvar By = $selenium.Byvar btnPath = "#main-content > article > div.r08-media-playlist.js-r08-media-playlist.r08-media-playlist--margin-64 > div.r08-media-playlist__tablist > "var loc = { main: By.id("main-content"), nav: By.className("header-site-nav"), issues: By.xpath("//*[@id='main-content']/article/div[11]/div/div[2]/div/div/div/ul/li[1]"), what_you_get: [ { service: 'apm', selector: By.css(btnPath + "button:nth-child(2)") }, { service: 'pixie', selector: By.css(btnPath + "button:nth-child(3)") }, { service: 'codestream', selector: By.css(btnPath + "button:nth-child(4)") }, { service: 'ml', selector: By.css(btnPath + "button:nth-child(5)") }, { service: 'logs', selector: By.css(btnPath + "button:nth-child(6)") }, { service: 'errors', selector: By.css(btnPath + "button:nth-child(7)") }, { service: 'infra', selector: By.css(btnPath + "button:nth-child(8)") }, { service: 'npm', selector: By.css(btnPath + "button:nth-child(9)") }, { service: 'browser', selector: By.css(btnPath + "button:nth-child(10)") }, { service: 'synthetics', selector: By.css(btnPath + "button:nth-child(11)") }, { service: 'aiops', selector: By.css(btnPath + "button:nth-child(12)") } ]}
// -------------------- FUNCTIONS// for backwards compatibility with legacy runtimesasync function waitForAndFindElement(locator, timeout) { const webElement = await $webDriver.wait( $selenium.until.elementLocated(locator), timeout, "Timed-out waiting for element to be located using: " + locator ) await $webDriver.wait( $selenium.until.elementIsVisible(webElement), timeout, "Timed-out waiting for element to be visible using ${element}" ) return await $webDriver.findElement(locator)}
// -------------------- START OF SCRIPTconsole.log("Starting synthetics script: " + SCRIPT_NAME)console.log("Default timeout is set to " + DEFAULT_TIMEOUT / 1000 + " seconds")console.log("URI: " + FULL_URL)
// Setting User Agent is not then-able, so we do this first (if defined and not default)if (USER_AGENT && 0 !== USER_AGENT.trim().length && USER_AGENT != "default") { $headers.add("User-Agent", USER_AGENT) console.log("Setting User-Agent to " + USER_AGENT)}
// Get browser capabilities and do nothing with it, so that we start with a then-able command$webDriver .getCapabilities() .then(function () {}) // Step 1 // if an error happens at any step, script execution is halted and a failed result is returned .then(function () { console.log("1. first step") return $webDriver.get(FULL_URL) }) // Step 2 .then(function () { console.log("2. waitForAndFindElement: ", loc.main.value) // verify id for main has loaded return waitForAndFindElement(loc.main, DEFAULT_TIMEOUT) }) // Step 3 .then(function () { console.log("3. waitForAndFindElement: ", loc.nav.value) // verify site nav has loaded return waitForAndFindElement(loc.nav, DEFAULT_TIMEOUT) }) // Step 4 .then(function () { console.log("4. findElement: ", loc.issues.value) return $webDriver.findElement(loc.issues, DEFAULT_TIMEOUT) }) // Step 5 .then(function (el) { console.log("5. getText") return el.getText() }) // Step 6 .then(function (text) { console.log("6. assert.equal: " + text + " == " + CHECK) assert.equal(text, CHECK, "validation text not found") }) // Step 7 (if assert is equal) .then(function () { console.log("7. verify what_you_get:") // loop through the what_you_get array // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach loc.what_you_get.forEach(function (nr, i, arr) { let n = i+1 console.log(" " + n + ". " + nr.service) // verify each asset has loaded return $webDriver.findElement(nr.selector, DEFAULT_TIMEOUT).catch(function (err) { console.error("Failure in Step 7." + n) throw err }) }) })