diff --git a/src/commands/run.ts b/src/commands/run.ts index 38a5306..b3fad34 100644 --- a/src/commands/run.ts +++ b/src/commands/run.ts @@ -1,7 +1,6 @@ import { RunOptions } from "../types"; -import { getLogger, DBService } from "../utils"; +import { getLogger, DBService, ApiService } from "../utils"; import { ChainContext } from "../domain"; -import { ApiService } from "../utils/api"; /** * Run the watch-tower 👀🐮 diff --git a/src/domain/addContract.ts b/src/domain/addContract.ts index 45959ff..a2d8773 100644 --- a/src/domain/addContract.ts +++ b/src/domain/addContract.ts @@ -3,6 +3,7 @@ import { getLogger, handleExecutionError, isComposableCowCompatible, + metrics, } from "../utils"; import { BytesLike, ethers } from "ethers"; @@ -20,17 +21,6 @@ import { import { ChainContext } from "./chainContext"; import { ConditionalOrderParams } from "@cowprotocol/cow-sdk"; -import { - addContractRunsTotal, - addContractsErrorsTotal, - addContractsRunDurationSeconds, - measureTime, - merkleRootTotal, - ownersTotal, - singleOrdersTotal, - activeOrdersTotal, - activeOwnersTotal, -} from "../utils/metrics"; /** * Listens to these events on the `ComposableCoW` contract: @@ -44,13 +34,13 @@ export async function addContract( event: ConditionalOrderCreatedEvent ) { const { chainId } = context; - await measureTime({ + await metrics.measureTime({ action: () => _addContract(context, event), labelValues: [chainId.toString()], - durationMetric: addContractsRunDurationSeconds, - totalRunsMetric: addContractRunsTotal, + durationMetric: metrics.addContractsRunDurationSeconds, + totalRunsMetric: metrics.addContractRunsTotal, errorHandler: handleExecutionError, - errorMetric: addContractsErrorsTotal, + errorMetric: metrics.addContractsErrorsTotal, }); } @@ -79,7 +69,7 @@ async function _addContract( registry ); if (added) { - ownersTotal.labels(context.chainId.toString()).inc(); + metrics.ownersTotal.labels(context.chainId.toString()).inc(); numContractsAdded++; } else { log.error( @@ -110,6 +100,7 @@ export async function _registerNewOrder( ): Promise<{ error: boolean; added: boolean }> { const log = getLogger("addContract:_registerNewOrder"); const { transactionHash: tx } = event; + const { network } = registry; let added = false; try { // Check if the log is a ConditionalOrderCreated event @@ -134,7 +125,7 @@ export async function _registerNewOrder( registry ); added = true; - singleOrdersTotal.labels(registry.network).inc(); + metrics.singleOrdersTotal.labels(network).inc(); } else if ( event.topics[0] == composableCow.getEventTopic("MerkleRootSet") ) { @@ -175,7 +166,7 @@ export async function _registerNewOrder( registry ); added = true; - merkleRootTotal.labels(registry.network).inc(); + metrics.merkleRootTotal.labels(network).inc(); } } } @@ -209,8 +200,9 @@ export function add( ) { const log = getLogger("addContract:add"); const { handler, salt, staticInput } = params; - if (registry.ownerOrders.has(owner)) { - const conditionalOrders = registry.ownerOrders.get(owner); + const { network, ownerOrders } = registry; + if (ownerOrders.has(owner)) { + const conditionalOrders = ownerOrders.get(owner); log.info( `Adding conditional order to already existing owner contract ${owner}`, { tx, handler, salt, staticInput } @@ -234,7 +226,7 @@ export function add( orders: new Map(), composableCow, }); - activeOrdersTotal.labels(registry.network).inc(); + metrics.activeOrdersTotal.labels(network).inc(); } } else { log.info(`Adding conditional order to new owner contract ${owner}:`, { @@ -247,8 +239,8 @@ export function add( owner, new Set([{ tx, params, proof, orders: new Map(), composableCow }]) ); - activeOwnersTotal.labels(registry.network).inc(); - activeOrdersTotal.labels(registry.network).inc(); + metrics.activeOwnersTotal.labels(network).inc(); + metrics.activeOrdersTotal.labels(network).inc(); } } diff --git a/src/domain/chainContext.ts b/src/domain/chainContext.ts index 2e27e67..1f88e53 100644 --- a/src/domain/chainContext.ts +++ b/src/domain/chainContext.ts @@ -22,15 +22,8 @@ import { DBService, getLogger, isRunningInKubernetesPod, + metrics, } from "../utils"; -import { - blockHeight, - blockProducingRate, - eventsProcessedTotal, - processBlockDurationSeconds, - reorgDepth, - reorgsTotal, -} from "../utils/metrics"; import { hexZeroPad } from "ethers/lib/utils"; import { FilterPolicy } from "../utils/filterPolicy"; @@ -183,7 +176,9 @@ export class ChainContext { const { pageSize } = this; // Set the block height metric - blockHeight.labels(chainId.toString()).set(lastProcessedBlock?.number ?? 0); + metrics.blockHeight + .labels(chainId.toString()) + .set(lastProcessedBlock?.number ?? 0); // Start watching from (not including) the last processed block (if any) let fromBlock = lastProcessedBlock @@ -269,7 +264,7 @@ export class ChainContext { await this.registry.write(); // Set the block height metric - blockHeight.labels(chainId.toString()).set(Number(blockNumber)); + metrics.blockHeight.labels(chainId.toString()).set(blockNumber); } catch (err) { log.error(`Error processing block ${blockNumber}`, err); } @@ -334,16 +329,16 @@ export class ChainContext { // Set the block time metric const _blockTime = block.timestamp - lastBlockReceived.timestamp; - blockProducingRate.labels(chainId.toString()).set(_blockTime); + metrics.blockProducingRate.labels(chainId.toString()).set(_blockTime); if ( blockNumber <= lastBlockReceived.number && block.hash !== lastBlockReceived.hash ) { // This is a re-org, so process the block again - reorgsTotal.labels(chainId.toString()).inc(); + metrics.reorgsTotal.labels(chainId.toString()).inc(); log.info(`Re-org detected, re-processing block ${blockNumber}`); - reorgDepth + metrics.reorgDepth .labels(chainId.toString()) .set(lastBlockReceived.number - blockNumber + 1); } @@ -361,7 +356,7 @@ export class ChainContext { // Block height metric this.registry.lastProcessedBlock = blockToRegistryBlock(block); this.registry.write(); - blockHeight.labels(chainId.toString()).set(Number(blockNumber)); + metrics.blockHeight.labels(chainId.toString()).set(blockNumber); } catch { log.error(`Error processing block ${blockNumber}`); } @@ -457,7 +452,7 @@ async function processBlock( blockTimestampOverride?: number ) { const { provider, chainId } = context; - const timer = processBlockDurationSeconds + const timer = metrics.processBlockDurationSeconds .labels(context.chainId.toString()) .startTimer(); const log = getLogger( @@ -481,7 +476,7 @@ async function processBlock( return false; }); log.info(`Result of "addContract": ${_formatResult(result)}`); - eventsProcessedTotal.labels(chainId.toString()).inc(); + metrics.eventsProcessedTotal.labels(chainId.toString()).inc(); } } diff --git a/src/domain/checkForAndPlaceOrder.ts b/src/domain/checkForAndPlaceOrder.ts index 36250cb..59755c6 100644 --- a/src/domain/checkForAndPlaceOrder.ts +++ b/src/domain/checkForAndPlaceOrder.ts @@ -30,18 +30,6 @@ import { formatEpoch, } from "@cowprotocol/cow-sdk"; import { ChainContext, SDK_BACKOFF_NUM_OF_ATTEMPTS } from "./chainContext"; -import { - pollingOnChainDurationSeconds, - activeOrdersTotal, - activeOwnersTotal, - orderBookDiscreteOrdersTotal, - orderBookErrorsTotal, - pollingOnChainChecksTotal, - pollingRunsTotal, - pollingUnexpectedErrorsTotal, - pollingOnChainEthersErrorsTotal, - measureTime, -} from "../utils/metrics"; import { FilterAction } from "../utils/filterPolicy"; import { validateOrder } from "../utils/filterOrder"; diff --git a/src/types/model.ts b/src/types/model.ts index 7da9aa3..cc7b94b 100644 --- a/src/types/model.ts +++ b/src/types/model.ts @@ -4,8 +4,7 @@ import { BytesLike, ethers } from "ethers"; import type { ConditionalOrderCreatedEvent } from "./generated/ComposableCoW"; import { ConditionalOrderParams, PollResult } from "@cowprotocol/cow-sdk"; -import { DBService } from "../utils"; -import { activeOrdersTotal, activeOwnersTotal } from "../utils/metrics"; +import { DBService, metrics } from "../utils"; // Standardise the storage key const LAST_NOTIFIED_ERROR_STORAGE_KEY = "LAST_NOTIFIED_ERROR"; @@ -167,12 +166,12 @@ export class Registry { .catch(() => null); // Return registry (on its latest version) - activeOwnersTotal.labels(network).set(ownerOrders.size); + metrics.activeOwnersTotal.labels(network).set(ownerOrders.size); const numOrders = Array.from(ownerOrders.values()).reduce( (acc, o) => acc + o.size, 0 ); - activeOrdersTotal.labels(network).set(numOrders); + metrics.activeOrdersTotal.labels(network).set(numOrders); return new Registry( ownerOrders, diff --git a/src/utils/contracts.ts b/src/utils/contracts.ts index 7e276bf..47d718b 100644 --- a/src/utils/contracts.ts +++ b/src/utils/contracts.ts @@ -8,7 +8,7 @@ import { SupportedChainId, } from "@cowprotocol/cow-sdk"; import { getLogger } from "./logging"; -import { pollingOnChainInvalidInterfacesTotal } from "./metrics"; +import { metrics } from "."; // Selectors that are required to be part of the contract's bytecode in order to be considered compatible const REQUIRED_SELECTORS = [ @@ -293,7 +293,6 @@ export function handleOnChainCustomError(params: { `Order for safe ${owner} where the Safe has swap guard enabled. Deleting order...` ); return dropOrder("The conditional order didn't pass the swap guard"); - // TODO: Add metrics to track this case CustomErrorSelectors.ORDER_NOT_VALID: const reason = msgWithSelector(parsedCustomError.message); log.info( @@ -333,7 +332,7 @@ export function handleOnChainCustomError(params: { log.debug( `Contract returned a non-compliant interface revert via getTradeableOrderWithSignature. Simulate: https://dashboard.tenderly.co/gp-v2/watch-tower-prod/simulator/new?network=${chainId}&contractAddress=${target}&rawFunctionInput=${callData}` ); - pollingOnChainInvalidInterfacesTotal.labels(...metricLabels).inc(); + metrics.pollingOnChainInvalidInterfacesTotal.labels(...metricLabels).inc(); return { result: PollResultCode.DONT_TRY_AGAIN, reason: "Order returned a non-compliant (invalid/erroneous) revert hint", diff --git a/src/utils/index.ts b/src/utils/index.ts index 9a66bc0..c5fbd7c 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -4,3 +4,5 @@ export * from "./poll"; export * from "./misc"; export * from "./db"; export * from "./logging"; +export * from "./api"; +export * as metrics from "./metrics";