Sentry(v20.12.1) K8S 雲原生架構探索,SENTRY FOR JAVASCRIPT Source Maps 詳解

為少發表於2021-01-15

系列

  1. Sentry-Go SDK 中文實踐指南
  2. 一起來刷 Sentry For Go 官方文件之 Enriching Events
  3. Snuba:Sentry 新的搜尋基礎設施(基於 ClickHouse 之上)
  4. Sentry 10 K8S 雲原生架構探索,Vue App 1 分鐘快速接入
  5. Sentry(v20.12.1) K8S雲原生架構探索,玩轉前/後端監控與事件日誌大資料分析,高效能高可用+可擴充套件可伸縮叢集部署
  6. Sentry(v20.12.1) K8S 雲原生架構探索,Sentry JavaScript SDK 三種安裝載入方式
  7. Sentry(v20.12.1) K8S 雲原生架構探索,SENTRY FOR JAVASCRIPT SDK 配置詳解
  8. Sentry(v20.12.1) K8S 雲原生架構探索, SENTRY FOR JAVASCRIPT 手動捕獲事件基本用法

Sentry 支援通過 source maps(原始碼對映)對 JavaScript 進行 un-minifying,這允許您以原始的未轉換形式檢視從堆疊跟蹤中獲得的原始碼上下文。這對於除錯壓縮後的程式碼(例如,UglifyJS)或從高階語言編譯的程式碼(如 TypeScriptES6)特別有用。

Sentry 將通過抓取堆疊跟蹤中的 URL 自動獲取原始碼(source code)和原始碼對映(source maps)。但是,您可能有正當的理由在 Sentry 中 disabling the JavaScript source fetching in Sentry(在 Sentry 中禁用 JavaScript 原始碼獲取)。

Capturing Source Maps

大多數現代 JavaScript 編譯器都支援 source maps。下面你會發現我們推薦的說明,但我們也提供了各種常用工具的說明:

  • Webpack
  • TypeScript
  • UglifyJS
  • SystemJS

我們建議使用 Sentry's Webpack plugin 來配置 source maps 並在構建過程中自動上傳它們:

npm install --save-dev @sentry/webpack-plugin
or
yarn add --dev @sentry/webpack-plugin

接下來,您需要為我們的 API 生成 access token。在您的組織設定中,導航到 Developer Settings,create a new internal integration,並提供一個適合您組織的名稱。重要: 選擇 Releases -> Admin,針對許可權。

Releases -> Admin 許可權在其他 API 文件中也稱為 'project:releases'。

你可以通過它的文件機制來配置 sentry-cli,或者在初始化外掛時簡單地繫結所需的引數:

const SentryWebpackPlugin = require("@sentry/webpack-plugin");

module.exports = {
  // other configuration
  configureWebpack: {
    plugins: [
      new SentryWebpackPlugin({
        // sentry-cli configuration
        authToken: process.env.SENTRY_AUTH_TOKEN,
        org: "exmaple-org",
        project: "example-project",

        // webpack specific configuration
        include: ".",
        ignore: ["node_modules", "webpack.config.js"],
      }),
    ],
  },
};

在 Vue 2.x 中,應使用 vue.config.js 而不是 webpack.config.js,並使用 include: "./dist" 而不是 include: "."

Hosting Publicly

預設情況下,Sentry 將在已編譯的 JavaScript 檔案中查詢源對映指令(source map directives),這些指令位於最後一行,並具有以下格式:

//# sourceMappingURL=<url>

當 Sentry 遇到這樣一個指令時,它將解析與它所在的原始檔相關的 source map URL,並嘗試使用 HTTP 請求獲取它。

例如,如果您有一個壓縮的 JavaScript 檔案位於 http://example.org/js/app.min.js,並且在該檔案的最後一行中,則找到以下指令:

//# sourceMappingURL=app.js.map

Sentry 將嘗試從 http://example.org/js/app.js.map 獲取 app.js.map

另外,在生成原始碼對映時,你可以指定原始碼對映所在的絕對 URL:

//# sourceMappingURL=http://example.org/js/app.js.map

雖然從伺服器使 source maps 可用於 Sentry 是最自然的整合(natural integration),但並不總是建議這樣做:

  • Sentry 可能並不總是能夠訪問您的伺服器。
  • 如果您沒有在您的 asset URLs 中指定版本,可能存在版本不匹配
  • 額外的延遲可能意味著源對映對所有錯誤都不可用。

由於這些原因,最好的做法是預先上傳 source maps 給 Sentry(見下文)。

Working Behind a Firewall

推薦的解決方案是將您的 source artifacts 上傳到 Sentry,但有時有必要允許來自 Sentry 內部 IP 的通訊。有關 Sentry 的公共IP 的更多資訊,請參見:IP Ranges

Secure Access to Source Maps

如果你想保密你的 source maps 並且選擇不直接上傳你的 source maps 到 Sentry,你可以在你的專案設定中啟用 “Security Token” 選項。

這將導致 Sentry 伺服器對來自 “Allowed Domains” 的 URL 的出站請求附加 HTTP 標頭 X-Sentry-Token 標頭:

GET /assets/bundle.min.js
X-Sentry-Token: {token}

token 是您在專案設定中定義的安全值。然後,您可以配置您的 web 伺服器,以允許在此 header/token 對 存在時訪問您的 source maps。你也可以覆蓋預設的 header 名稱(X-Sentry-Token)並使用 HTTP Basic Authentication,例如通過傳遞 Authorization: Basic {encoded_password}

Multiple Origins

可以從多個來源訪問 web 應用程式的情況並不少見。例如:

  • 網站可以在 httpshttp 上執行
  • 地理位置網址:例如 https://us.example.com, https://eu.example.com
  • 多個靜態 CDN:例如 https://static1.example.com, https://static2.example.com
  • 客戶特定的域(domains)/子域(subdomains

在這種情況下,相同的 JavaScript 和 source map 檔案可能位於兩個或多個不同的源。在這種情況下,我們建議在路徑上使用特殊的波浪號(~)字首。

例如,如果你有以下內容:

  • https://static1.example.com/js/app.js
  • https://static2.example.com/js/app.js

您可以使用 ~/js/app.js 的 URL 進行上傳。 這將告訴 Sentry 忽略域,並將 artifact 用於任何來源。

此外,您還可以使用多個名稱上傳同一檔案。在後臺,Sentry 會將這些重複資料刪除。

~字首告訴 Sentry,對於給定的 URL,任何 路徑為 /js/app.js 的協議和主機名的組合都應該使用這個工件(artifact)。只有當您的 source/source map 檔案在所有可能的 protocol/hostname 組合上都相同時,才使用此方法。如果找到完整的 URL, Sentry 將優先使用,高於波浪字首路徑。

Tools

SystemJS

SystemJS 是 Angular 2 專案的預設模組載入器。SystemJS 構建工具可用於 bundle,transpile 和 minify 用於生產環境的原始碼,並可配置為輸出 source maps。

builder.bundle("src/app.js", "dist/app.min.js", {
  minify: true,
  sourceMaps: true,
  sourceMapContents: true,
});

上面的示例配置會將您原始的(original),未經轉換(un-transformed)的原始碼內聯到生成的 source map 檔案中。 Sentry要求 source map(s) 和原始原始檔都執行反向轉換。如果您選擇不內聯原始檔,則除了源對映外,還必須使這些原始檔對 Sentry 可用(請參見下文)。

TypeScript

TypeScript 編譯器可以輸出 source maps。將 sourceRoot 屬性配置為 /,以從生成的原始碼引用中去除構建路徑字首。這允許 Sentry 匹配原始檔相對於你的源根資料夾:

{
  "compilerOptions": {
    "sourceMap": true,
    "inlineSources": true,
    "sourceRoot": "/"
  }
}

UglifyJS

UglifyJS 是一種流行的工具,可用於壓縮生產原始碼。通過消除空格,重寫變數名,刪除無效程式碼分支等,它可以大大減少檔案的大小。

我們強烈建議您使用更高階別的 bundler(或 transpiler),因為 UglifyJS 配置可能會變得非常複雜,無法達到預期的效果。

如果你正在使用 UglifyJS 來壓縮你的原始碼,下面的命令將額外生成一個 source map,將壓縮的程式碼對映回原始原始碼:

uglifyjs app.js \
  -o app.min.js.map \
  --source-map url=app.min.js.map,includeSources

Webpack

Webpack 是一個強大的構建工具,可以解析、捆綁和壓縮 JavaScript 模組。它還支援各種 loaders 來轉換高階語言、引用樣式表或包含靜態資源。

Sentry 提供了一個方便的 Webpack plugin,可以配置 source maps,並在構建時將它們上傳到 Sentry。對於上傳源到 Sentry,推薦使用這個過程:

npm install --save-dev @sentry/webpack-plugin
or
yarn add --dev @sentry/webpack-plugin

您可以通過其 documented mechanisms 來配置 sentry-cli,或者在初始化外掛時僅繫結必需的引數:

const SentryWebpackPlugin = require("@sentry/webpack-plugin");

module.exports = {
  // other configuration
  configureWebpack: {
    plugins: [
      new SentryWebpackPlugin({
        // sentry-cli configuration
        authToken: process.env.SENTRY_AUTH_TOKEN,
        org: "exmaple-org",
        project: "example-project",

        // webpack specific configuration
        include: ".",
        ignore: ["node_modules", "webpack.config.js"],
      }),
    ],
  },
};

在 Vue 2.x 中,應使用 vue.config.js 而不是 webpack.config.js,並使用 include: "./dist" 而不是 include: "."

SentryWebpackPlugin 設定為最後一個正在執行的外掛,否則,該外掛接收到的結果 source maps 可能不是最終的。

Advanced Usage

如果您希望手動上傳 source maps,請將 Webpack 配置為輸出 source maps:

module.exports = {
  output: {
    path: path.join(__dirname, "dist"),
    filename: "[name].js",
    sourceMapFilename: "[name].js.map",
  },
  // other configuration
};

如果使用 SourceMapDevToolPlugin 進行 source map 生成的更細粒度控制,請關閉 noSources,以便 Sentry 在事件堆疊跟蹤中顯示正確的原始碼上下文。

此外,Webpack 外掛將自動設定 window.SENTRY_RELEASE,因此您的 Sentry.init 呼叫將不需要更新。

Troubleshooting

Source maps 有時可能很難上手。如果您遇到問題:

Verify a release is configured in your SDK

要定位和應用已上傳的 source maps,需要通過 CLI 或 API 建立 release(以及上傳的正確 artifacts),並且需要在 SDK 配置中指定新建立的 release 的名稱。

要驗證這一點,請從 Sentry UI 開啟 issue 並檢查是否配置了 release。如果螢幕右側的 Release 旁邊顯示 "not configured" 或 "N/A"(或如果你沒有看到一個 release 標籤在標籤列表),則需要返回並 tag your errors。如果設定正確,您將看到 "Release: my_example_release"。

Verify artifacts are uploaded

一旦您的 release 被正確配置並且問題被標記,您可以通過導航到 [Project] » Project Settings » Source Maps 來找到上傳到 Sentry 的工件(artifacts)。

此外,請確保所有必要的檔案都可用。為了讓 Sentry 去 de-minify 你的堆疊跟蹤,您必須同時提供兩個壓縮的檔案(例如,app.min.js)以及相應的 source maps。如果 source map 檔案不包含原始 source code(sourcesContent),則必須另外提供原始 source code。或者,sentry-cli 會自動將原始碼(如果缺少)嵌入到 source maps 中。

Verify sourceMappingURL is present

一些 CDN 自動從靜態檔案(包括 JavaScript 檔案)中刪除註釋。這可能會導致 JavaScript 檔案中沒有 sourceMappingURL 指令,因為它被視為註釋。例如,CloudFlare 有一個名為 Auto-Minify 的功能,如果它被啟用,它將剝離 sourceMappingURL

仔細檢查部署的最終 JavaScript 檔案是否有 sourceMappingURL

或者,您可以在壓縮的檔案上設定 SourceMap HTTP header,而不是 sourceMappingURL。如果存在此標頭,Sentry 將使用它來發現 source map 的位置。

Verify artifact names match sourceMappingURL value

bundled 或 minified 的 JavaScript 檔案的最後一行的 sourceMappingURL 註釋告訴Sentry(或瀏覽器)在哪裡找到相應的 source map。這可以是絕對的 URL,相對路徑或檔名本身。將工件(artifacts)上傳到 Sentry 時,必須使用檔案解析到的值來命名 source map 檔案。

也就是說,如果你的檔案類似於:

// -- end script.min.js
//# sourceMappingURL=script.min.js.map

並託管在 http://example.com/js/script.min.js 上,然後 Sentry 將在 http://example.com/js/script.min.js.map 上查詢 source map 檔案。因此,您上傳的工件(artifact)必須命名為 http://example.com/js/script.min.js.map (或 ~/js/script.min.js.map)。

或者,如果你的檔案類似於:

//-- end script.min.js
//# sourceMappingURL=https://example.com/dist/js/script.min.js.map

然後你上傳的工件(artifact)也應該命名為 https://example.com/dist/js/script.min.js.map (或者 ~/dist/js/script.min.js.map )。

最後,如果你的檔案類似於:

//-- end script.min.js
//# sourceMappingURL=../maps/script.min.js.map

然後你上傳的工件應該命名為 https://example.com/dist/maps/script.min.js.map (或者 ~/dist/maps/script.min.js.map)。

Verify artifact names match stack trace frames

如果您上傳了 source maps,但它們沒有應用到 Sentry 中的某個 issue 中的程式碼中,請檢視事件的 JSON 並查詢 abs_path,以檢視我們試圖解析檔案的確切位置 — 例如,http://localhost:8000/scripts/script.js(對於堆疊跟蹤中的每一幀,abs_path 將出現一次 - 將其與未被非 deminified 的檔案匹配。)。在事件發生日期旁邊的 issue 頁面頂部可以找到一個指向 JSON 檢視的連結。上載的工件名稱(uploaded artifact names)必須與這些值匹配。

如果您的 dynamic values in your path(路徑中有動態值)(例如:https://www.site.com/{some_value}/scripts/script.js),則可能需要使用 rewriteFrames integration 來更改 abs_path 值。

Using sentry-cli

如果您的 sourceMappingURL 註釋類似於:

// -- end script.min.js (located at http://localhost:8000/scripts/script.min.js)
//# sourceMappingURL=script.min.js.map

正確上傳這些檔案的示例,sentry-cli 命令如下所示(假設您位於 /scripts 目錄中,並從一個更高的目錄執行 Web 伺服器,這就是為什麼我們使用 --url-prefix 選項):

sentry-cli releases files VERSION upload-sourcemaps . --url-prefix '~/scripts'

此命令上傳當前目錄中的所有 JavaScript 檔案。Sentry 中的 Artifacts 頁面現在應如下所示:

~/scripts/script.js
~/scripts/script.min.js
~/scripts/script.min.js.map

或者,您可以指定要上傳的檔案。 例如:

sentry-cli releases files VERSION upload-sourcemaps script.min.js script.min.js.map --url-prefix '~/scripts'

您也可以使用絕對 URL 上傳它。例如:

sentry-cli releases files VERSION upload-sourcemaps . --url-prefix 'http://localhost:8000/scripts'

Using the API

您也可以使用我們的API 來上傳工件,遵循這裡解釋的相同命名約定。

curl -X POST \
  https://sentry.io/api/0/organizations/ORG_SLUG/releases/VERSION/files/ \
  -H 'Authorization: Bearer AUTH_TOKEN' \
  -H 'content-type: multipart/form-data' \
  -F file=@script.min.js.map \
  -F 'name=~/scripts/script.min.js.map'

Using the ~

~ 在 Sentry 中用於替換 scheme 和 domain。這不是一個問題!

http://example.com/dist/js/script.js 將匹配 ~/dist/js/script.jshttp://example.com/dist/js/script.js

但是將不匹配 ~/script.js

Verify artifacts are uploaded before errors occur

Sentry 希望在某個 release 中出現錯誤之前,將 source code 和 source maps 上傳到 Sentry。

如果您在 Sentry 捕獲錯誤之後上傳工件,Sentry 將不會返回並追溯地對這些錯誤應用任何源註釋。只有在工件上傳後觸發的新錯誤才會受到影響。

Verify your source maps are built correctly

我們維護了一個線上驗證工具,可以用來測試您的 source maps 與 hosted(託管) 源:https://sourcemaps.io

另外,如果你正在使用 Sentry CLI 上傳 source maps 到 Sentry,你可以使用 --validate 命令列選項來驗證你的 source maps 是否正確。

Verify your source maps work locally

如果發現 Sentry 沒有正確對映檔名,行或列對映,則應驗證 source maps 是否在本地執行。為此,您可以將 Node.js 與Mozilla 的 source-map library 一起使用。

首先,將 source-map 作為 npm 模組全域性安裝:

npm install -g source-map

然後,編寫一個指令碼,該指令碼讀取您的 source map 檔案並測試對映。這是一個例子:

var fs = require("fs"),
  path = require("path"),
  sourceMap = require("source-map");

// file output by Webpack, Uglify, and so forth
var GENERATED_FILE = path.join(".", "app.min.js.map");

// line and column located in your generated file (for example, the source of your error
// from your minified file)
var GENERATED_LINE_AND_COLUMN = { line: 1, column: 1000 };

var rawSourceMap = fs.readFileSync(GENERATED_FILE).toString();
new sourceMap.SourceMapConsumer(rawSourceMap).then(function(smc) {
  var pos = smc.originalPositionFor(GENERATED_LINE_AND_COLUMN);

  // should see something like:
  // { source: 'original.js', line: 57, column: 9, name: 'myfunc' }
  console.log(pos);
});

如果您通過 Sentry 在本地獲得相同(不正確)的結果,請仔細檢查您的 source map 生成配置。

Verify your source files are not too large

對於單個 artifact,Sentry 接受的最大檔案大小為 40 MB

使用者通常會達到此限制,因為他們在臨時構建階段傳輸原始檔。例如,在 Webpack/Browserify 合併所有原始檔之後,但在壓縮之前。如果可能,請傳送原始原始檔。

Verify artifacts are not gzipped

Sentry API 當前僅適用於以純文字(UTF-8 編碼)上傳的 source maps 和 source files。如果檔案以壓縮格式(例如 gzip)上傳,則將無法正確解釋它們。

這種情況有時會發生在生成預壓縮小檔案的構建指令碼和外掛中。例如,Webpack 的壓縮外掛。您需要禁用這些外掛,並在將生成的 source maps/source files 上傳到 Sentry 後執行壓縮。

Verify workers are sharing the same volume as web (if running as docker on premise)

Sentry 在其 workers 中進行 source map 計算。這意味著 workers 需要訪問通過前端上傳的檔案。仔細檢查 cron workers 和 web workers 是否可以從同一個磁碟讀/寫檔案。

Uploading Source Maps

我們建議將上傳 source maps 作為構建過程的一部分,但您也可以將它們與原始檔一起公開提供。

建議的上傳 source maps 的方法是使用 sentry-cli。如果您使用 Sentry Wizard 來設定專案,則它已經建立了所有必要的配置以上傳 source maps。否則,請遵循 CLI 配置文件來設定您的專案。

您需要設定構建系統以建立 release 並附加各種原始檔。為了使 Sentry 縮小堆疊跟蹤的大小,必須同時提供縮小的檔案(例如app.min.js)和相應的源對映。如果源對映檔案不包含原始原始碼(sourcesContent),則還必須提供原始原始檔。另外,sentry-cli 將自動將源(如果缺少)嵌入到 source maps 中。

Sentry 使用 Releases 將正確的 source maps 與您的事件進行匹配。要建立新 release,請執行以下命令(例如,在釋出期間):

sentry-cli releases new <release_name>

release 名稱必須是在您的組織內唯一的,並且與 SDK 初始化程式碼中的 release 選項匹配。然後,使用 upload-sourcemaps 命令掃描資料夾中的 source maps,進行處理並將其上傳到 Sentry。

sentry-cli releases files <release_name> upload-sourcemaps /path/to/files

您可以通過導航找到上傳到 Sentry 的工件:[Project] » Project Settings » Source Maps

此命令會將所有以 .js 和 .map 結尾的檔案上傳到指定的 release。如果您想更改這些副檔名(例如,上傳 typescript 源),請使用 --ext 選項:

sentry-cli releases files <release_name> upload-sourcemaps --ext ts --ext map /path/to/files

到目前為止,版本處於草稿狀態((“unreleased”)。 一旦所有 source maps 都已上傳,並且您的應用已成功釋出,請使用以下命令完成 release:

sentry-cli releases finalize <release_name>

為了方便起見,您也可以將 --finalize flag 傳遞給 new 命令,該命令將立即完成 release。

你不必一定上傳原始檔(由 source maps 引用),但是沒有它們,分組演算法就不會那麼強大,UI 也不會顯示任何上下文相關的原始檔。

有關更多資訊,請參閱我們 Releases API documentation

web 應用程式可以從多個來源訪問並不少見。請參閱我們關於如何處理此問題的多個來源的文件。

Validating Files

要確保 source maps 本身是有效的,並且正確上傳,這可能是一個相當具有挑戰性的問題。為了幫助實現這一點,我們維護了一個線上驗證工具,可用於根據託管源測試源對映:https://sourcemaps.io

此外,當使用 sentry-cli 上傳源對映時,可以在中使用 --validate 標誌,這將嘗試本地解析源對映並查詢引用。請注意,在某些已知情況下,當設定正確時,validate 標誌將指示失敗(如果您有對外部源對映的引用,則驗證工具將指示失敗)。

除了驗證步驟之外,您還可以檢查以下內容:

  • 確保您的檔案的 URL 字首正確。這很容易出錯。
  • 為 minimized 的檔案上傳匹配的源對映。
  • 確保伺服器上的 minified 檔案確實引用了您的檔案。

中文文件陸續同步到:

我是為少。
微信:uuhells123。
公眾號:黑客下午茶。
謝謝點贊支援???!

相關文章