Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: metrics module #140

Merged
merged 1 commit into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/commands/run.ts
Original file line number Diff line number Diff line change
@@ -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 👀🐮
Expand Down
38 changes: 15 additions & 23 deletions src/domain/addContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
getLogger,
handleExecutionError,
isComposableCowCompatible,
metrics,
} from "../utils";
import { BytesLike, ethers } from "ethers";

Expand All @@ -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:
Expand All @@ -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,
});
}

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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
Expand All @@ -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")
) {
Expand Down Expand Up @@ -175,7 +166,7 @@ export async function _registerNewOrder(
registry
);
added = true;
merkleRootTotal.labels(registry.network).inc();
metrics.merkleRootTotal.labels(network).inc();
}
}
}
Expand Down Expand Up @@ -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 }
Expand All @@ -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}:`, {
Expand All @@ -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();
}
}

Expand Down
29 changes: 13 additions & 16 deletions src/domain/chainContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -269,7 +264,9 @@ 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(Number(blockNumber));
} catch (err) {
log.error(`Error processing block ${blockNumber}`, err);
}
Expand Down Expand Up @@ -334,16 +331,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);
}
Expand All @@ -361,7 +358,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}`);
}
Expand Down Expand Up @@ -457,7 +454,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(
Expand All @@ -481,7 +478,7 @@ async function processBlock(
return false;
});
log.info(`Result of "addContract": ${_formatResult(result)}`);
eventsProcessedTotal.labels(chainId.toString()).inc();
metrics.eventsProcessedTotal.labels(chainId.toString()).inc();
}
}

Expand Down
33 changes: 11 additions & 22 deletions src/domain/checkForAndPlaceOrder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
getLogger,
pollConditionalOrder,
handleOnChainCustomError,
metrics,
} from "../utils";
import {
ConditionalOrder as ConditionalOrderSDK,
Expand All @@ -30,18 +31,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";

Expand Down Expand Up @@ -230,7 +219,7 @@ export async function checkForAndPlaceOrder(
const action = deleted ? "Stop Watching" : "Failed to stop watching";

log.debug(`${action} conditional order from TX ${conditionalOrder.tx}`);
activeOrdersTotal.labels(chainId.toString()).dec();
metrics.activeOrdersTotal.labels(chainId.toString()).dec();
}
}

Expand All @@ -239,7 +228,7 @@ export async function checkForAndPlaceOrder(
for (const [owner, conditionalOrders] of Array.from(ownerOrders.entries())) {
if (conditionalOrders.size === 0) {
ownerOrders.delete(owner);
activeOwnersTotal.labels(chainId.toString()).dec();
metrics.activeOwnersTotal.labels(chainId.toString()).dec();
}
}

Expand Down Expand Up @@ -274,7 +263,7 @@ async function _processConditionalOrder(
const id = ConditionalOrderSDK.leafToId(conditionalOrder.params);
const metricLabels = [chainId.toString(), handler, owner, id];
try {
pollingRunsTotal.labels(...metricLabels).inc();
metrics.pollingRunsTotal.labels(...metricLabels).inc();

const proof = conditionalOrder.proof
? conditionalOrder.proof.path.map((c) => c.toString())
Expand Down Expand Up @@ -310,7 +299,7 @@ async function _processConditionalOrder(
// Unsupported Order Type (unknown handler)
// For now, fallback to legacy behavior
// TODO: Decide in the future what to do. Probably, move the error handling to the SDK and kill the poll Legacy
pollResult = await measureTime({
pollResult = await metrics.measureTime({
action: () =>
_pollLegacy(
context,
Expand All @@ -321,8 +310,8 @@ async function _processConditionalOrder(
orderRef
),
labelValues: metricLabels,
durationMetric: pollingOnChainDurationSeconds,
totalRunsMetric: pollingOnChainChecksTotal,
durationMetric: metrics.pollingOnChainDurationSeconds,
totalRunsMetric: metrics.pollingOnChainChecksTotal,
});
}

Expand Down Expand Up @@ -389,7 +378,7 @@ async function _processConditionalOrder(
signature,
};
} catch (e: any) {
pollingUnexpectedErrorsTotal.labels(...metricLabels).inc();
metrics.pollingUnexpectedErrorsTotal.labels(...metricLabels).inc();
return {
result: PollResultCode.UNEXPECTED_ERROR,
error: e,
Expand Down Expand Up @@ -488,7 +477,7 @@ async function _placeOrder(params: {
log.debug(`Post order details`, postOrder);
if (!dryRun) {
const orderUid = await orderBook.sendOrder(postOrder);
orderBookDiscreteOrdersTotal.labels(...metricLabels).inc();
metrics.orderBookDiscreteOrdersTotal.labels(...metricLabels).inc();
log.info(`API response`, { orderUid });
}
} catch (error: any) {
Expand Down Expand Up @@ -544,7 +533,7 @@ function _handleOrderBookError(
metricLabels: string[]
): Omit<PollResultSuccess, "order" | "signature"> | PollResultErrors {
const apiError = body?.errorType as OrderPostError.errorType;
orderBookErrorsTotal
metrics.orderBookErrorsTotal
.labels(...metricLabels, status.toString(), apiError)
.inc();
if (status === 400) {
Expand Down Expand Up @@ -649,7 +638,7 @@ async function _pollLegacy(
// We can only get here from some provider / ethers failure. As the contract hasn't had it's say
// we will defer to try again.
log.error(`ethers/call Unexpected error`, error);
pollingOnChainEthersErrorsTotal.labels(...metricLabels).inc();
metrics.pollingOnChainEthersErrorsTotal.labels(...metricLabels).inc();
return {
result: PollResultCode.TRY_NEXT_BLOCK,
reason:
Expand Down
7 changes: 3 additions & 4 deletions src/types/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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,
Expand Down
5 changes: 2 additions & 3 deletions src/utils/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ export * from "./poll";
export * from "./misc";
export * from "./db";
export * from "./logging";
export * from "./api";
export * as metrics from "./metrics";
Loading