UNPKG

hardhat

Version:

Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.

170 lines (137 loc) 4.82 kB
import { HardhatError, HardhatPluginError, } from "@nomicfoundation/hardhat-errors"; import { createDebug } from "@nomicfoundation/hardhat-utils/debug"; import { ProviderError, UnknownError, } from "../../../builtin-plugins/network-manager/provider-errors.js"; import { UsingHardhat2PluginError } from "../../../using-hardhat2-plugin-errors.js"; import { getHardhatVersion } from "../../../utils/package.js"; import { isTelemetryAllowed } from "../telemetry-permissions.js"; const log = createDebug("hardhat:core:cli:telemetry:sentry:reporter"); // export const SENTRY_DSN = // "https://d578a176729662a28e7a8da268d36912@o385026.ingest.us.sentry.io/4507685793103872"; // DEV export const SENTRY_DSN = "https://572b03708e298427cc72fc26dac1e8b2@o385026.ingest.us.sentry.io/4508780138856448"; // PROD /** * @deprecated Use packages/hardhat/src/internal/cli/telemetry/error-reporter/reporter.ts * instead. */ export async function sendErrorTelemetry( error: Error, hint?: { unhandled?: boolean; mechanismType?: string }, ): Promise<boolean> { const instance = await Reporter.getInstance(); return await instance.reportErrorViaSubprocess(error, hint); } export function setCliHardhatConfigPath(configPath: string): void { Reporter.setHardhatConfigPath(configPath); } // ATTENTION: this function is exported for testing, do not directly use it in production export function _testResetReporter(): void { Reporter.deleteInstance(); } class Reporter { // GENERAL EXPLANATION: // 1) The 'reportError' function collects the error and passes it to our custom Sentry transporter. // 2) The custom transporter receives the JavaScript error serialized by Sentry. // 3) This serialized error is then passed to a detached subprocess, which anonymizes all the information before sending it to Sentry. static #hardhatConfigPath?: string; static #instance: Reporter | undefined; readonly #telemetryEnabled: boolean; private constructor(telemetryAllowed: boolean) { this.#telemetryEnabled = telemetryAllowed; } public static setHardhatConfigPath(configPath: string): void { this.#hardhatConfigPath = configPath; } public static async getInstance(): Promise<Reporter> { if (this.#instance !== undefined) { return this.#instance; } const telemetryAllowed = await isTelemetryAllowed(); this.#instance = new Reporter(telemetryAllowed); if (!telemetryAllowed) { // No need to initialize Sentry because telemetry is disabled log("Reporter not initialized because telemetry is not allowed"); return this.#instance; } log("Initializing Reporter instance"); const { setExtra } = await import("@sentry/core"); const hardhatVersion = await getHardhatVersion(); const { init } = await import("./init.js"); const { createDetachedProcessTransport } = await import("./transport.js"); const release = `hardhat@${hardhatVersion}`; const environment = "production"; init({ dsn: SENTRY_DSN, transport: createDetachedProcessTransport( SENTRY_DSN, release, environment, () => this.#hardhatConfigPath, ), release, environment, }); setExtra("nodeVersion", process.version); setExtra("hardhatVersion", hardhatVersion); return this.#instance; } public static deleteInstance(): void { // ATTENTION: only for testing this.#instance = undefined; } public async reportErrorViaSubprocess( error: Error, hint?: { unhandled?: boolean; mechanismType?: string }, ): Promise<boolean> { if (!(await this.#shouldBeReported(error))) { log("Error not send: this type of error should not be reported"); return false; } const { captureException, flush } = await import("@sentry/core"); log("Capturing exception"); captureException( error, hint !== undefined ? { mechanism: { type: hint.mechanismType ?? "generic", handled: hint.unhandled !== true, }, } : undefined, ); await flush(); return true; } async #shouldBeReported(error: Error): Promise<boolean> { if (!this.#telemetryEnabled) { return false; } if ( HardhatError.isHardhatError(error) && !error.descriptor.shouldBeReported ) { return false; } if (error instanceof UsingHardhat2PluginError) { return false; } if (HardhatPluginError.isHardhatPluginError(error)) { // Don't log errors from third-party plugins return false; } if ( ProviderError.isProviderError(error) && error.code !== UnknownError.CODE ) { // We don't report known network related errors return false; } return true; } }