Skip to content

Commit

Permalink
Enhance Metric Monitor functionality by introducing MetricMonitorCrit…
Browse files Browse the repository at this point in the history
…eria, updating MetricMonitorResponse, and refining telemetry monitoring logic
  • Loading branch information
simlarsen committed Dec 10, 2024
1 parent 450488e commit b26cf4e
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import DataToProcess from "../DataToProcess";
import CompareCriteria from "./CompareCriteria";
import { CheckOn, CriteriaFilter } from "Common/Types/Monitor/CriteriaFilter";

export default class LogMonitorCriteria {
export default class MetricMonitorCriteria {
public static async isMonitorInstanceCriteriaFilterMet(input: {
dataToProcess: DataToProcess;
criteriaFilter: CriteriaFilter;
}): Promise<string | null> {

// Metric Monitoring Checks

let threshold: number | string | undefined | null =
Expand Down
2 changes: 2 additions & 0 deletions Common/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import AggregatedResult from "../../BaseDatabase/AggregatedResult";
import InBetween from "../../BaseDatabase/InBetween";
import MetricsViewConfig from "../../Metrics/MetricsViewConfig";
import ObjectID from "../../ObjectID";

export default interface MetricMonitorResponse {
startAndEndDate?: InBetween<Date>;
metricResult: Array<AggregatedResult>;
metricViewConfig: MetricsViewConfig;
monitorId: ObjectID;
Expand Down
26 changes: 1 addition & 25 deletions Dashboard/src/Components/Form/Monitor/MonitorStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,28 +152,6 @@ const MonitorStepElement: FunctionComponent<ComponentProps> = (
}
};

const fetchMetricAttributes: PromiseVoidFunction =
async (): Promise<void> => {
const attributeRepsonse: HTTPResponse<JSONObject> | HTTPErrorResponse =
await API.post(
URL.fromString(APP_API_URL.toString()).addRoute(
"/telemetry/metrics/get-attributes",
),
{},
{
...ModelAPI.getCommonHeaders(),
},
);

if (attributeRepsonse instanceof HTTPErrorResponse) {
throw attributeRepsonse;
} else {
const attributes: Array<string> = attributeRepsonse.data[
"attributes"
] as Array<string>;
setAttributeKeys(attributes);
}
};

const fetchTelemetryServices: PromiseVoidFunction =
async (): Promise<void> => {
Expand Down Expand Up @@ -216,9 +194,7 @@ const MonitorStepElement: FunctionComponent<ComponentProps> = (
await fetchSpanAttributes();
}

if (props.monitorType === MonitorType.Metrics) {
await fetchMetricAttributes();
}
// For metrics monitor we don't need attributes because the metric view component fetches it for us. So we don't need to fetch it here.
} catch (err) {
setError(API.getFriendlyErrorMessage(err as Error));
}
Expand Down
7 changes: 4 additions & 3 deletions Dashboard/src/Pages/Monitor/View/Index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import PageMap from "../../../Utils/PageMap";
import LogMonitorPreview from "../../../Components/Monitor/LogMonitor/LogMonitorPreview";
import TraceTable from "../../../Components/Traces/TraceTable";
import { MonitorStepTraceMonitorUtil } from "Common/Types/Monitor/MonitorStepTraceMonitor";
import MetricMonitorPreview from "../../../Components/Monitor/MetricMonitor/MetricMonitorPreview";

const MonitorView: FunctionComponent<PageComponentProps> = (): ReactElement => {
const modelId: ObjectID = Navigation.getLastParamAsObjectID();
Expand Down Expand Up @@ -577,10 +578,10 @@ const MonitorView: FunctionComponent<PageComponentProps> = (): ReactElement => {
"Preview of the metrics that match the filter of this monitor."
}
>
<LogMonitorPreview
monitorStepLogMonitor={
<MetricMonitorPreview
monitorStepMetricMonitor={
monitor.monitorSteps.data?.monitorStepsInstanceArray[0]?.data
?.logMonitor
?.metricMonitor
}
/>
</Card>
Expand Down
6 changes: 6 additions & 0 deletions Dashboard/src/Utils/Form/Monitor/CriteriaFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,12 @@ export default class CriteriaFilterUtil {
});
}

if (monitorType === MonitorType.Metrics) {
options = options.filter((i: DropdownOption) => {
return i.value === CheckOn.MetricValue;
});
}

return options;
}

Expand Down
94 changes: 89 additions & 5 deletions Worker/Jobs/TelemetryMonitor/MonitorTelemetryMonitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ import MonitorStepTraceMonitor, {
MonitorStepTraceMonitorUtil,
} from "Common/Types/Monitor/MonitorStepTraceMonitor";
import SpanService from "Common/Server/Services/SpanService";
import MetricMonitorResponse from "Common/Types/Monitor/MetricMonitor/MetricMonitorResponse";
import MonitorStepMetricMonitor from "Common/Types/Monitor/MonitorStepMetricMonitor";
import RollingTimeUtil from "Common/Types/RollingTime/RollingTimeUtil";
import RollingTime from "Common/Types/RollingTime/RollingTime";
import InBetween from "Common/Types/BaseDatabase/InBetween";
import AggregatedResult from "Common/Types/BaseDatabase/AggregatedResult";
import MetricService from "Common/Server/Services/MetricService";
import MetricsAggregationType from "Common/Types/Metrics/MetricsAggregationType";
import Dictionary from "Common/Types/Dictionary";

RunCron(
"LogMonitor:MonitorLogMonitor",
Expand Down Expand Up @@ -104,7 +113,7 @@ RunCron(
logger.debug(telemetryMonitors);

const monitorResponses: Array<
Promise<LogMonitorResponse | TraceMonitorResponse>
Promise<LogMonitorResponse | TraceMonitorResponse | MetricMonitorResponse>
> = [];

for (const monitor of telemetryMonitors) {
Expand Down Expand Up @@ -134,8 +143,9 @@ RunCron(
}
}

const responses: Array<LogMonitorResponse | TraceMonitorResponse> =
await Promise.all(monitorResponses);
const responses: Array<
LogMonitorResponse | TraceMonitorResponse | MetricMonitorResponse
> = await Promise.all(monitorResponses);

for (const response of responses) {
MonitorResourceUtil.monitorResource(response);
Expand All @@ -147,13 +157,17 @@ type MonitorTelemetryMonitorFunction = (data: {
monitorStep: MonitorStep;
monitorType: MonitorType;
monitorId: ObjectID;
}) => Promise<LogMonitorResponse | TraceMonitorResponse>;
}) => Promise<
LogMonitorResponse | TraceMonitorResponse | MetricMonitorResponse
>;

const monitorTelemetryMonitor: MonitorTelemetryMonitorFunction = async (data: {
monitorStep: MonitorStep;
monitorType: MonitorType;
monitorId: ObjectID;
}): Promise<LogMonitorResponse | TraceMonitorResponse> => {
}): Promise<
LogMonitorResponse | TraceMonitorResponse | MetricMonitorResponse
> => {
const { monitorStep, monitorType, monitorId } = data;

if (monitorType === MonitorType.Logs) {
Expand All @@ -170,6 +184,13 @@ const monitorTelemetryMonitor: MonitorTelemetryMonitorFunction = async (data: {
});
}

if (monitorType === MonitorType.Metrics) {
return monitorMetric({
monitorStep,
monitorId,
});
}

throw new BadDataException("Monitor type is not supported");
};

Expand Down Expand Up @@ -208,6 +229,69 @@ const monitorTrace: MonitorTraceFunction = async (data: {
};
};

type MonitorMetricFunction = (data: {
monitorStep: MonitorStep;
monitorId: ObjectID;
}) => Promise<MetricMonitorResponse>;

const monitorMetric: MonitorMetricFunction = async (data: {
monitorStep: MonitorStep;
monitorId: ObjectID;
}): Promise<MetricMonitorResponse> => {
// Monitor traces
const metricMonitorConfig: MonitorStepMetricMonitor | undefined =
data.monitorStep.data?.metricMonitor;

if (!metricMonitorConfig) {
throw new BadDataException("Metric config is missing");
}

const startAndEndDate: InBetween<Date> =
RollingTimeUtil.convertToStartAndEndDate(
metricMonitorConfig.rollingTime || RollingTime.Past1Minute,
);

const finalResult: Array<AggregatedResult> = [];

for (const queryConfig of metricMonitorConfig.metricViewConfig.queryConfigs) {
const aggregatedResults: AggregatedResult = await MetricService.aggregateBy(
{
query: {
time: startAndEndDate,
name: queryConfig.metricQueryData.filterData.metricName,
attributes: queryConfig.metricQueryData.filterData
.attributes as Dictionary<string | number | boolean>,
},
aggregationType:
(queryConfig.metricQueryData.filterData
.aggegationType as MetricsAggregationType) ||
MetricsAggregationType.Avg,
aggregateColumnName: "value",
aggregationTimestampColumnName: "time",
startTimestamp:
(startAndEndDate?.startValue as Date) ||
OneUptimeDate.getCurrentDate(),
endTimestamp:
(startAndEndDate?.endValue as Date) || OneUptimeDate.getCurrentDate(),
limit: LIMIT_PER_PROJECT,
skip: 0,
groupBy: queryConfig.metricQueryData.groupBy,
props: {
isRoot: true,
},
},
);

finalResult.push(aggregatedResults);
}

return {
metricViewConfig: metricMonitorConfig.metricViewConfig,
startAndEndDate: startAndEndDate,
metricResult: finalResult,
monitorId: data.monitorId,
};
};
type MonitorLogsFunction = (data: {
monitorStep: MonitorStep;
monitorId: ObjectID;
Expand Down

0 comments on commit b26cf4e

Please sign in to comment.