mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
Merge branch 'merge-dir'
This commit is contained in:
@@ -4,19 +4,19 @@ import LIMIT_MAX, { LIMIT_PER_PROJECT } from "Common/Types/Database/LimitMax";
|
||||
import MonitorType from "Common/Types/Monitor/MonitorType";
|
||||
import { EVERY_MINUTE } from "Common/Utils/CronTime";
|
||||
import MonitorService from "CommonServer/Services/MonitorService";
|
||||
import QueryHelper from "CommonServer/Types/AnalyticsDatabase/QueryHelper";
|
||||
import logger from "CommonServer/Utils/Logger";
|
||||
import MonitorResourceUtil from "CommonServer/Utils/Monitor/MonitorResource";
|
||||
import Monitor from "Common/Models/DatabaseModels/Monitor";
|
||||
import CronTab from "CommonServer/Utils/CronTab";
|
||||
import MonitorStep from "Common/Types/Monitor/MonitorStep";
|
||||
import LogMonitorResponse from "Common/Types/Monitor/LogMonitor/LogMonitorResponse";
|
||||
import MonitorStepLogMonitor from "Common/Types/Monitor/MonitorStepLogMonitor";
|
||||
import MonitorStepLogMonitor, {
|
||||
MonitorStepLogMonitorUtil,
|
||||
} from "Common/Types/Monitor/MonitorStepLogMonitor";
|
||||
import BadDataException from "Common/Types/Exception/BadDataException";
|
||||
import LogService from "CommonServer/Services/LogService";
|
||||
import Query from "CommonServer/Types/AnalyticsDatabase/Query";
|
||||
import Log from "Common/Models/AnalyticsModels/Log";
|
||||
import Search from "Common/Types/BaseDatabase/Search";
|
||||
import PositiveNumber from "Common/Types/PositiveNumber";
|
||||
import JSONFunctions from "Common/Types/JSONFunctions";
|
||||
import DatabaseQueryHelper from "CommonServer/Types/Database/QueryHelper";
|
||||
@@ -176,39 +176,7 @@ const monitorLogs: MonitorLogsFunction = async (data: {
|
||||
throw new BadDataException("Log query is missing");
|
||||
}
|
||||
|
||||
const query: Query<Log> = {};
|
||||
|
||||
if (logQuery.attributes) {
|
||||
query.attributes = logQuery.attributes;
|
||||
}
|
||||
|
||||
if (logQuery.body) {
|
||||
query.body = new Search(logQuery.body);
|
||||
}
|
||||
|
||||
if (logQuery.severityTexts && logQuery.severityTexts.length > 0) {
|
||||
query.severityText = QueryHelper.any(
|
||||
logQuery.severityTexts as Array<string>,
|
||||
);
|
||||
}
|
||||
|
||||
if (logQuery.telemetryServiceIds && logQuery.telemetryServiceIds.length > 0) {
|
||||
query.serviceId = QueryHelper.any(logQuery.telemetryServiceIds);
|
||||
}
|
||||
|
||||
if (!logQuery.lastXSecondsOfLogs) {
|
||||
throw new BadDataException("Last X seconds of logs is missing");
|
||||
}
|
||||
|
||||
const lastXSecondsOfLogs: number = logQuery.lastXSecondsOfLogs;
|
||||
|
||||
const endDate: Date = OneUptimeDate.getCurrentDate();
|
||||
const startDate: Date = OneUptimeDate.addRemoveSeconds(
|
||||
endDate,
|
||||
lastXSecondsOfLogs * -1,
|
||||
);
|
||||
|
||||
query.time = QueryHelper.inBetween(startDate, endDate);
|
||||
const query: Query<Log> = MonitorStepLogMonitorUtil.toQuery(logQuery);
|
||||
|
||||
const countLogs: PositiveNumber = await LogService.countBy({
|
||||
query: query,
|
||||
|
||||
@@ -37,10 +37,14 @@ import {
|
||||
ManyToOne,
|
||||
} from "typeorm";
|
||||
import TelemetryType from "../../Types/Telemetry/TelemetryType";
|
||||
import Query from "../../Types/BaseDatabase/Query";
|
||||
import Log from "../AnalyticsModels/Log";
|
||||
import Span from "../AnalyticsModels/Span";
|
||||
import Metric from "../AnalyticsModels/Metric";
|
||||
|
||||
export interface TelemetryIncidentQuery {
|
||||
telemetryType: TelemetryType;
|
||||
telemetryQuery: JSONObject;
|
||||
telemetryQuery: Query<Log> | Query<Span> | Query<Metric>;
|
||||
}
|
||||
|
||||
@EnableDocumentation()
|
||||
|
||||
@@ -25,8 +25,24 @@ export default class InBetween extends SerializableObject {
|
||||
endValue: number | Date | string,
|
||||
) {
|
||||
super();
|
||||
this.endValue = endValue;
|
||||
this.startValue = startValue;
|
||||
|
||||
if (
|
||||
typeof startValue === "string" &&
|
||||
OneUptimeDate.isValidDateString(startValue)
|
||||
) {
|
||||
this.startValue = OneUptimeDate.fromString(startValue);
|
||||
} else {
|
||||
this.startValue = startValue;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof endValue === "string" &&
|
||||
OneUptimeDate.isValidDateString(endValue)
|
||||
) {
|
||||
this.endValue = OneUptimeDate.fromString(endValue);
|
||||
} else {
|
||||
this.endValue = endValue;
|
||||
}
|
||||
}
|
||||
|
||||
public override toJSON(): JSONObject {
|
||||
|
||||
@@ -935,6 +935,10 @@ export default class OneUptimeDate {
|
||||
return this.getGmtOffsetFriendlyString(offset) + " " + timezone;
|
||||
}
|
||||
|
||||
public static isValidDateString(date: string): boolean {
|
||||
return moment(date).isValid();
|
||||
}
|
||||
|
||||
public static getGmtOffsetFriendlyString(offset: number): string {
|
||||
const hours: number = Math.abs(offset) / 60;
|
||||
const minutes: number = Math.abs(offset) % 60;
|
||||
|
||||
@@ -261,6 +261,8 @@ export default class JSONFunctions {
|
||||
return val;
|
||||
} else if (val instanceof DatabaseProperty) {
|
||||
return val;
|
||||
} else if (val instanceof SerializableObject) {
|
||||
return val;
|
||||
} else if (
|
||||
val &&
|
||||
typeof val === Typeof.Object &&
|
||||
|
||||
@@ -234,6 +234,7 @@ export default class BaseAnalyticsAPI<
|
||||
let groupBy: GroupBy<AnalyticsDataModel> = {};
|
||||
|
||||
if (req.body) {
|
||||
|
||||
query = JSONFunctions.deserialize(
|
||||
req.body["query"],
|
||||
) as Query<AnalyticsDataModel>;
|
||||
|
||||
@@ -41,7 +41,9 @@ import ProbeApiIngestResponse from "Common/Types/Probe/ProbeApiIngestResponse";
|
||||
import ProbeMonitorResponse from "Common/Types/Probe/ProbeMonitorResponse";
|
||||
import Typeof from "Common/Types/Typeof";
|
||||
import MonitorMetricsByMinute from "Common/Models/AnalyticsModels/MonitorMetricsByMinute";
|
||||
import Incident from "Common/Models/DatabaseModels/Incident";
|
||||
import Incident, {
|
||||
TelemetryIncidentQuery,
|
||||
} from "Common/Models/DatabaseModels/Incident";
|
||||
import IncidentSeverity from "Common/Models/DatabaseModels/IncidentSeverity";
|
||||
import IncidentStateTimeline from "Common/Models/DatabaseModels/IncidentStateTimeline";
|
||||
import Monitor from "Common/Models/DatabaseModels/Monitor";
|
||||
@@ -50,6 +52,8 @@ import MonitorStatusTimeline from "Common/Models/DatabaseModels/MonitorStatusTim
|
||||
import OnCallDutyPolicy from "Common/Models/DatabaseModels/OnCallDutyPolicy";
|
||||
import OneUptimeDate from "Common/Types/Date";
|
||||
import LogMonitorCriteria from "./Criteria/LogMonitorCriteria";
|
||||
import LogMonitorResponse from "Common/Types/Monitor/LogMonitor/LogMonitorResponse";
|
||||
import TelemetryType from "Common/Types/Telemetry/TelemetryType";
|
||||
|
||||
export default class MonitorResourceUtil {
|
||||
public static async monitorResource(
|
||||
@@ -333,12 +337,24 @@ export default class MonitorResourceUtil {
|
||||
}`,
|
||||
);
|
||||
|
||||
let telemetryQuery: TelemetryIncidentQuery | undefined = undefined;
|
||||
|
||||
if (dataToProcess && (dataToProcess as LogMonitorResponse).logQuery) {
|
||||
telemetryQuery = {
|
||||
telemetryQuery: (dataToProcess as LogMonitorResponse).logQuery,
|
||||
telemetryType: TelemetryType.Log,
|
||||
};
|
||||
}
|
||||
|
||||
await this.criteriaMetCreateIncidentsAndUpdateMonitorStatus({
|
||||
monitor: monitor,
|
||||
rootCause: response.rootCause,
|
||||
dataToProcess: dataToProcess,
|
||||
autoResolveCriteriaInstanceIdIncidentIdsDictionary,
|
||||
criteriaInstance: criteriaInstanceMap[response.criteriaMetId!]!,
|
||||
props: {
|
||||
telemetryQuery: telemetryQuery,
|
||||
},
|
||||
});
|
||||
} else if (
|
||||
!response.criteriaMetId &&
|
||||
@@ -649,6 +665,9 @@ export default class MonitorResourceUtil {
|
||||
autoResolveCriteriaInstanceIdIncidentIdsDictionary: Dictionary<
|
||||
Array<string>
|
||||
>;
|
||||
props: {
|
||||
telemetryQuery?: TelemetryIncidentQuery | undefined;
|
||||
};
|
||||
}): Promise<void> {
|
||||
// criteria filters are met, now process the actions.
|
||||
|
||||
@@ -790,6 +809,10 @@ export default class MonitorResourceUtil {
|
||||
|
||||
incident.isCreatedAutomatically = true;
|
||||
|
||||
if (input.props.telemetryQuery) {
|
||||
incident.telemetryQuery = input.props.telemetryQuery;
|
||||
}
|
||||
|
||||
if (
|
||||
input.dataToProcess &&
|
||||
(input.dataToProcess as ProbeMonitorResponse).probeId
|
||||
|
||||
@@ -386,10 +386,12 @@ export default class ModelAPI {
|
||||
);
|
||||
|
||||
if (result.isSuccess()) {
|
||||
return BaseModel.fromJSONObject(
|
||||
const baseModel: TBaseModel = BaseModel.fromJSONObject(
|
||||
result.data as JSONObject,
|
||||
data.modelType,
|
||||
);
|
||||
|
||||
return baseModel;
|
||||
}
|
||||
|
||||
this.checkStatusCode(result);
|
||||
|
||||
@@ -35,7 +35,7 @@ const DashboardLogsViewer: FunctionComponent<ComponentProps> = (
|
||||
type RefreshQueryFunction = () => Query<Log>;
|
||||
|
||||
const refreshQuery: RefreshQueryFunction = (): Query<Log> => {
|
||||
let query: Query<Log> = {};
|
||||
const query: Query<Log> = {};
|
||||
|
||||
if (props.telemetryServiceIds && props.telemetryServiceIds.length > 0) {
|
||||
query.serviceId = new Includes(props.telemetryServiceIds);
|
||||
@@ -49,11 +49,10 @@ const DashboardLogsViewer: FunctionComponent<ComponentProps> = (
|
||||
query.spanId = new Includes(props.spanIds);
|
||||
}
|
||||
|
||||
if (props.logQuery) {
|
||||
query = {
|
||||
...query,
|
||||
...props.logQuery,
|
||||
};
|
||||
if (props.logQuery && Object.keys(props.logQuery).length > 0) {
|
||||
for (const key in props.logQuery) {
|
||||
(query as any)[key] = (props.logQuery as any)[key] as any;
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
|
||||
@@ -28,7 +28,9 @@ import BaseAPI from "CommonUI/src/Utils/API/API";
|
||||
import GlobalEvent from "CommonUI/src/Utils/GlobalEvents";
|
||||
import ModelAPI, { ListResult } from "CommonUI/src/Utils/ModelAPI/ModelAPI";
|
||||
import Navigation from "CommonUI/src/Utils/Navigation";
|
||||
import Incident from "Common/Models/DatabaseModels/Incident";
|
||||
import Incident, {
|
||||
TelemetryIncidentQuery,
|
||||
} from "Common/Models/DatabaseModels/Incident";
|
||||
import IncidentSeverity from "Common/Models/DatabaseModels/IncidentSeverity";
|
||||
import IncidentState from "Common/Models/DatabaseModels/IncidentState";
|
||||
import IncidentStateTimeline from "Common/Models/DatabaseModels/IncidentStateTimeline";
|
||||
@@ -41,6 +43,10 @@ import React, {
|
||||
useState,
|
||||
} from "react";
|
||||
import UserElement from "../../../Components/User/User";
|
||||
import Card from "CommonUI/src/Components/Card/Card";
|
||||
import DashboardLogsViewer from "../../../Components/Logs/LogsViewer";
|
||||
import TelemetryType from "Common/Types/Telemetry/TelemetryType";
|
||||
import JSONFunctions from "Common/Types/JSONFunctions";
|
||||
|
||||
const IncidentView: FunctionComponent<
|
||||
PageComponentProps
|
||||
@@ -55,6 +61,9 @@ const IncidentView: FunctionComponent<
|
||||
const [error, setError] = useState<string>("");
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
const [telemetryQuery, setTelemetryQuery] =
|
||||
useState<TelemetryIncidentQuery | null>(null);
|
||||
|
||||
const fetchData: PromiseVoidFunction = async (): Promise<void> => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
@@ -96,6 +105,23 @@ const IncidentView: FunctionComponent<
|
||||
sort: {},
|
||||
});
|
||||
|
||||
const incident: Incident | null = await ModelAPI.getItem({
|
||||
id: modelId,
|
||||
modelType: Incident,
|
||||
select: {
|
||||
telemetryQuery: true,
|
||||
},
|
||||
});
|
||||
|
||||
let telemetryQuery: TelemetryIncidentQuery | null = null;
|
||||
|
||||
if (incident?.telemetryQuery) {
|
||||
telemetryQuery = JSONFunctions.deserialize(
|
||||
incident?.telemetryQuery as any,
|
||||
) as any;
|
||||
}
|
||||
|
||||
setTelemetryQuery(telemetryQuery);
|
||||
setIncidentStates(incidentStates.data as IncidentState[]);
|
||||
setIncidentStateTimeline(
|
||||
incidentTimelines.data as IncidentStateTimeline[],
|
||||
@@ -660,6 +686,19 @@ const IncidentView: FunctionComponent<
|
||||
modelId: modelId,
|
||||
}}
|
||||
/>
|
||||
|
||||
{telemetryQuery && telemetryQuery.telemetryType === TelemetryType.Log && (
|
||||
<div>
|
||||
<Card title={"Logs"} description={"Logs for this incident."}>
|
||||
<DashboardLogsViewer
|
||||
id="logs-preview"
|
||||
logQuery={telemetryQuery.telemetryQuery}
|
||||
limit={10}
|
||||
noLogsMessage="No logs found"
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user