mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
refactor: Update LogSeverity enum to use string values instead of enum values
This refactor updates the LogSeverity enum to use string values instead of enum values. This change allows for better compatibility and flexibility when working with log severity levels. The enum values have been replaced with corresponding string values. Files modified: - Common/Types/Log/LogSeverity.ts - Ingestor/API/OTelIngest.ts - Ingestor/API/FluentIngest.ts - Model/AnalyticsModels/Log.ts - CommonUI/src/Components/LogsViewer/LogItem.tsx - CommonUI/src/Components/LogsViewer/LogsViewer.tsx - CommonUI/src/Components/Filters/DropdownFilter.tsx - Common/Types/ObjectID.ts - CommonUI/src/Components/Filters/FiltersForm.tsx
This commit is contained in:
11
Common/Types/Log/LogSeverity.ts
Normal file
11
Common/Types/Log/LogSeverity.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
enum LogSeverity {
|
||||
Unspecified = "Unspecified",
|
||||
Information = "Information",
|
||||
Warning = "Warning",
|
||||
Error = "Error",
|
||||
Trace = "Trace",
|
||||
Debug = "Debug",
|
||||
Fatal = "Fatal",
|
||||
}
|
||||
|
||||
export default LogSeverity;
|
||||
@@ -10,6 +10,7 @@ import JSONFunctions from "../JSONFunctions";
|
||||
import ObjectID from "../ObjectID";
|
||||
import Port from "../Port";
|
||||
import MonitorCriteria from "./MonitorCriteria";
|
||||
import MonitorStepLogMonitor, { MonitorStepLogMonitorUtil } from "./MonitorStepLogMonitor";
|
||||
import MonitorType from "./MonitorType";
|
||||
import BrowserType from "./SyntheticMonitors//BrowserType";
|
||||
import ScreenSizeType from "./SyntheticMonitors/ScreenSizeType";
|
||||
@@ -35,6 +36,9 @@ export interface MonitorStepType {
|
||||
// this is for synthetic monitors.
|
||||
screenSizeTypes?: Array<ScreenSizeType> | undefined;
|
||||
browserTypes?: Array<BrowserType> | undefined;
|
||||
|
||||
// Log monitor type.
|
||||
logMonitor?: MonitorStepLogMonitor | undefined;
|
||||
}
|
||||
|
||||
export default class MonitorStep extends DatabaseProperty {
|
||||
@@ -54,6 +58,7 @@ export default class MonitorStep extends DatabaseProperty {
|
||||
customCode: undefined,
|
||||
screenSizeTypes: undefined,
|
||||
browserTypes: undefined,
|
||||
logMonitor: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -77,6 +82,7 @@ export default class MonitorStep extends DatabaseProperty {
|
||||
customCode: undefined,
|
||||
screenSizeTypes: undefined,
|
||||
browserTypes: undefined,
|
||||
logMonitor: undefined,
|
||||
};
|
||||
|
||||
return monitorStep;
|
||||
@@ -133,6 +139,11 @@ export default class MonitorStep extends DatabaseProperty {
|
||||
return this;
|
||||
}
|
||||
|
||||
public setLogMonitor(logMonitor: MonitorStepLogMonitor): MonitorStep {
|
||||
this.data!.logMonitor = logMonitor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setCustomCode(customCode: string): MonitorStep {
|
||||
this.data!.customCode = customCode;
|
||||
return this;
|
||||
@@ -157,6 +168,7 @@ export default class MonitorStep extends DatabaseProperty {
|
||||
customCode: undefined,
|
||||
screenSizeTypes: undefined,
|
||||
browserTypes: undefined,
|
||||
lgoMonitor: undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -240,6 +252,7 @@ export default class MonitorStep extends DatabaseProperty {
|
||||
customCode: this.data.customCode || undefined,
|
||||
screenSizeTypes: this.data.screenSizeTypes || undefined,
|
||||
browserTypes: this.data.browserTypes || undefined,
|
||||
logMonitor: this.data.logMonitor ? MonitorStepLogMonitorUtil.toJSON(this.data.logMonitor) : undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -328,6 +341,9 @@ export default class MonitorStep extends DatabaseProperty {
|
||||
screenSizeTypes:
|
||||
(json["screenSizeTypes"] as Array<ScreenSizeType>) || undefined,
|
||||
browserTypes: (json["browserTypes"] as Array<BrowserType>) || undefined,
|
||||
logMonitor: json["logMonitor"]
|
||||
? (json["logMonitor"] as JSONObject)
|
||||
: undefined,
|
||||
}) as any;
|
||||
|
||||
return monitorStep;
|
||||
|
||||
48
Common/Types/Monitor/MonitorStepLogMonitor.ts
Normal file
48
Common/Types/Monitor/MonitorStepLogMonitor.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import Dictionary from "../Dictionary";
|
||||
import { JSONObject } from "../JSON";
|
||||
import LogSeverity from "../Log/LogSeverity";
|
||||
import ObjectID from "../ObjectID";
|
||||
|
||||
export default interface MonitorStepLogMonitor {
|
||||
attributes: Dictionary<string | number | boolean>;
|
||||
body: string;
|
||||
severityText: Array<LogSeverity>;
|
||||
telemetryServiceId: Array<ObjectID>;
|
||||
lastXSecondsOfLogs: number;
|
||||
}
|
||||
|
||||
export class MonitorStepLogMonitorUtil {
|
||||
|
||||
public static getDefault(): MonitorStepLogMonitor {
|
||||
return {
|
||||
attributes: {},
|
||||
body: "",
|
||||
severityText: [],
|
||||
telemetryServiceId: [],
|
||||
lastXSecondsOfLogs: 60,
|
||||
};
|
||||
}
|
||||
|
||||
public static fromJSON(json: JSONObject): MonitorStepLogMonitor {
|
||||
return {
|
||||
attributes:
|
||||
(json["attributes"] as Dictionary<string | number | boolean>) || {},
|
||||
body: json["body"] as string,
|
||||
severityText: json["severityText"] as Array<LogSeverity>,
|
||||
telemetryServiceId: ObjectID.fromJSONArray(
|
||||
json["telemetryServiceId"] as Array<JSONObject>,
|
||||
),
|
||||
lastXSecondsOfLogs: json["lastXSecondsOfLogs"] as number,
|
||||
};
|
||||
}
|
||||
|
||||
public static toJSON(monitor: MonitorStepLogMonitor): JSONObject {
|
||||
return {
|
||||
attributes: monitor.attributes,
|
||||
body: monitor.body,
|
||||
severityText: monitor.severityText,
|
||||
telemetryServiceId: ObjectID.toJSONArray(monitor.telemetryServiceId),
|
||||
lastXSecondsOfLogs: monitor.lastXSecondsOfLogs,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,11 @@ enum MonitorType {
|
||||
// These two monitor types are same but we are keeping them separate for now - this is for marketing purposes
|
||||
SyntheticMonitor = "Synthetic Monitor",
|
||||
CustomJavaScriptCode = "Custom JavaScript Code",
|
||||
|
||||
// Telemetry monitor types
|
||||
Logs = "Logs",
|
||||
Metrics = "Metrics",
|
||||
Traces = "Traces",
|
||||
}
|
||||
|
||||
export default MonitorType;
|
||||
@@ -99,6 +104,23 @@ export class MonitorTypeHelper {
|
||||
description:
|
||||
"This monitor type lets you run custom JavaScript code on a schedule.",
|
||||
},
|
||||
{
|
||||
monitorType: MonitorType.Logs,
|
||||
title: "Logs",
|
||||
description: "This monitor type lets you monitor logs from any source.",
|
||||
},
|
||||
{
|
||||
monitorType: MonitorType.Metrics,
|
||||
title: "Metrics",
|
||||
description:
|
||||
"This monitor type lets you monitor metrics from any source.",
|
||||
},
|
||||
{
|
||||
monitorType: MonitorType.Traces,
|
||||
title: "Traces",
|
||||
description:
|
||||
"This monitor type lets you monitor traces from any source.",
|
||||
},
|
||||
];
|
||||
|
||||
return monitorTypeProps;
|
||||
|
||||
@@ -47,6 +47,12 @@ export default class ObjectID extends DatabaseProperty {
|
||||
return new this(UUID.generate());
|
||||
}
|
||||
|
||||
public static toJSONArray(ids: Array<ObjectID>): Array<JSONObject> {
|
||||
return ids.map((id: ObjectID) => {
|
||||
return id.toJSON();
|
||||
});
|
||||
}
|
||||
|
||||
protected static override toDatabase(
|
||||
value: ObjectID | FindOperator<ObjectID>,
|
||||
): string | null {
|
||||
@@ -76,6 +82,12 @@ export default class ObjectID extends DatabaseProperty {
|
||||
throw new BadDataException("Invalid JSON: " + JSON.stringify(json));
|
||||
}
|
||||
|
||||
public static fromJSONArray(json: Array<JSONObject>): Array<ObjectID> {
|
||||
return json.map((value: JSONObject) => {
|
||||
return ObjectID.fromJSON(value);
|
||||
});
|
||||
}
|
||||
|
||||
protected static override fromDatabase(_value: string): ObjectID | null {
|
||||
if (_value) {
|
||||
return new ObjectID(_value);
|
||||
|
||||
@@ -9,6 +9,7 @@ export interface ComponentProps<T extends GenericObject> {
|
||||
filter: Filter<T>;
|
||||
onFilterChanged?: undefined | ((filterData: FilterData<T>) => void);
|
||||
filterData: FilterData<T>;
|
||||
isMultiSelect?: boolean | undefined;
|
||||
}
|
||||
|
||||
type DropdownFilterFunction = <T extends GenericObject>(
|
||||
@@ -50,7 +51,7 @@ const DropdownFilter: DropdownFilterFunction = <T extends GenericObject>(
|
||||
}
|
||||
}}
|
||||
value={dropdownValue}
|
||||
isMultiSelect={false}
|
||||
isMultiSelect={props.isMultiSelect || false}
|
||||
placeholder={`Filter by ${filter.title}`}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@ import Button, { ButtonStyleType } from "../Button/Button";
|
||||
import ComponentLoader from "../ComponentLoader/ComponentLoader";
|
||||
import ErrorMessage from "../ErrorMessage/ErrorMessage";
|
||||
import FieldLabelElement from "../Forms/Fields/FieldLabel";
|
||||
import FieldType from "../Types/FieldType";
|
||||
import BooleanFilter from "./BooleanFilter";
|
||||
import DateFilter from "./DateFilter";
|
||||
import DropdownFilter from "./DropdownFilter";
|
||||
@@ -74,6 +75,9 @@ const FiltersForm: FiltersFormFunction = <T extends GenericObject>(
|
||||
filter={filter}
|
||||
filterData={props.filterData}
|
||||
onFilterChanged={changeFilterData}
|
||||
isMultiSelect={
|
||||
filter.type === FieldType.MultiSelectDropdown
|
||||
}
|
||||
/>
|
||||
|
||||
<EntityFilter
|
||||
|
||||
@@ -2,7 +2,8 @@ import CopyTextButton from "../CopyTextButton/CopyTextButton";
|
||||
import OneUptimeDate from "Common/Types/Date";
|
||||
import Dictionary from "Common/Types/Dictionary";
|
||||
import JSONFunctions from "Common/Types/JSONFunctions";
|
||||
import Log, { LogSeverity } from "Model/AnalyticsModels/Log";
|
||||
import Log from "Model/AnalyticsModels/Log";
|
||||
import LogSeverity from "Common/Types/Log/LogSeverity";
|
||||
import TelemetryService from "Model/Models/TelemetryService";
|
||||
import React, { FunctionComponent, ReactElement, useEffect } from "react";
|
||||
|
||||
|
||||
@@ -1,280 +0,0 @@
|
||||
import DropdownUtil from "../../Utils/Dropdown";
|
||||
import Button, { ButtonStyleType } from "../Button/Button";
|
||||
// import TelemetryService from 'Model/Models/TelemetryService';
|
||||
import CodeEditor from "../CodeEditor/CodeEditor";
|
||||
import Dropdown, { DropdownValue } from "../Dropdown/Dropdown";
|
||||
import ErrorMessage from "../ErrorMessage/ErrorMessage";
|
||||
import FieldLabelElement from "../Forms/Fields/FieldLabel";
|
||||
import Input, { InputType } from "../Input/Input";
|
||||
import CodeType from "Common/Types/Code/CodeType";
|
||||
import OneUptimeDate from "Common/Types/Date";
|
||||
import IconProp from "Common/Types/Icon/IconProp";
|
||||
import { LogSeverity } from "Model/AnalyticsModels/Log";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
|
||||
export interface FilterOption {
|
||||
searchText?: string | undefined;
|
||||
logSeverity?: LogSeverity | undefined;
|
||||
startTime?: Date | undefined;
|
||||
endTime?: Date | undefined;
|
||||
}
|
||||
|
||||
export interface ComponentProps {
|
||||
onFilterChanged: (filterOptions: FilterOption) => void;
|
||||
onAutoScrollChanged: (turnOnAutoScroll: boolean) => void;
|
||||
// telemetryServices?: Array<TelemetryService>;
|
||||
}
|
||||
|
||||
const LogsFilters: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
): ReactElement => {
|
||||
const [filterOptions, setFilterOptions] = React.useState<FilterOption>({});
|
||||
|
||||
const [turnOnAutoScroll, setTurnOnAutoScroll] = React.useState<boolean>(true);
|
||||
const [showMoreFilters, setShowMoreFilters] = React.useState<boolean>(false);
|
||||
const [isSqlQuery] = React.useState<boolean>(false);
|
||||
|
||||
const showAutoScrollButton: boolean =
|
||||
!isSqlQuery && !showMoreFilters && !filterOptions.searchText;
|
||||
const showSearchButton: boolean = Boolean(
|
||||
showMoreFilters || filterOptions.searchText,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="shadow sm:rounded-md">
|
||||
<div className="bg-white py-6 px-4 sm:p-6">
|
||||
<div>
|
||||
<div className="flex space-x-2 justify-between">
|
||||
<div className="w-full mr-2">
|
||||
{!isSqlQuery && (
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<FieldLabelElement title="Search Logs" required={true} />
|
||||
<Input
|
||||
placeholder="Search"
|
||||
onChange={(value: string) => {
|
||||
setFilterOptions({
|
||||
...filterOptions,
|
||||
searchText: value,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{showMoreFilters && (
|
||||
<div>
|
||||
<FieldLabelElement title="Log Severity" required={true} />
|
||||
<Dropdown
|
||||
onChange={(
|
||||
value: DropdownValue | Array<DropdownValue> | null,
|
||||
) => {
|
||||
if (value === null) {
|
||||
setFilterOptions({
|
||||
...filterOptions,
|
||||
logSeverity: undefined,
|
||||
});
|
||||
} else {
|
||||
setFilterOptions({
|
||||
...filterOptions,
|
||||
logSeverity: value.toString() as LogSeverity,
|
||||
});
|
||||
}
|
||||
}}
|
||||
options={DropdownUtil.getDropdownOptionsFromEnum(
|
||||
LogSeverity,
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showMoreFilters && (
|
||||
<div className="flex space-x-2 w-full">
|
||||
<div className="w-1/2">
|
||||
<FieldLabelElement title="Start Time" required={true} />
|
||||
<Input
|
||||
placeholder="Start Time"
|
||||
onChange={(value: string) => {
|
||||
setFilterOptions({
|
||||
...filterOptions,
|
||||
startTime: value
|
||||
? OneUptimeDate.fromString(value)
|
||||
: undefined,
|
||||
});
|
||||
}}
|
||||
type={InputType.DATETIME_LOCAL}
|
||||
/>
|
||||
{filterOptions.endTime && !filterOptions.startTime && (
|
||||
<ErrorMessage error="Start Time is required." />
|
||||
)}
|
||||
</div>
|
||||
<div className="w-1/2">
|
||||
<FieldLabelElement title="End Time" required={true} />
|
||||
<Input
|
||||
placeholder="End Time"
|
||||
onChange={(value: string) => {
|
||||
setFilterOptions({
|
||||
...filterOptions,
|
||||
endTime: value
|
||||
? OneUptimeDate.fromString(value)
|
||||
: undefined,
|
||||
});
|
||||
}}
|
||||
type={InputType.DATETIME_LOCAL}
|
||||
/>
|
||||
{filterOptions.startTime && !filterOptions.endTime && (
|
||||
<ErrorMessage error="End Time is required." />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{isSqlQuery && (
|
||||
<div>
|
||||
<div className="space-y-1">
|
||||
<FieldLabelElement
|
||||
title="SQL Query"
|
||||
required={true}
|
||||
description="Enter a SQL query to filter logs."
|
||||
/>
|
||||
<CodeEditor
|
||||
type={CodeType.SQL}
|
||||
placeholder="SQL Query"
|
||||
onChange={(value: string) => {
|
||||
setFilterOptions({
|
||||
searchText: value,
|
||||
});
|
||||
}}
|
||||
showLineNumbers={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{showAutoScrollButton && (
|
||||
<div>
|
||||
<div className="mt-7 -ml-5 justify-end flex w-44">
|
||||
{!turnOnAutoScroll && (
|
||||
<Button
|
||||
title="Start Autoscroll"
|
||||
icon={IconProp.Play}
|
||||
onClick={() => {
|
||||
setTurnOnAutoScroll(true);
|
||||
props.onAutoScrollChanged(true);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{turnOnAutoScroll && (
|
||||
<Button
|
||||
title="Stop Autoscroll"
|
||||
icon={IconProp.Stop}
|
||||
onClick={() => {
|
||||
setTurnOnAutoScroll(false);
|
||||
props.onAutoScrollChanged(false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isSqlQuery && (
|
||||
<div className="">
|
||||
<div className="mt-12 -ml-8 justify-end flex w-44">
|
||||
<Button title="Search with SQL" onClick={() => {}} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{showSearchButton && (
|
||||
<div className="">
|
||||
<div className="mt-7 -ml-20 justify-end flex w-44">
|
||||
<Button
|
||||
title="Search"
|
||||
onClick={() => {
|
||||
props.onFilterChanged(filterOptions);
|
||||
}}
|
||||
icon={IconProp.Search}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="flex justify-between -ml-2 -mr-2">
|
||||
<div className="flex">
|
||||
{!isSqlQuery && (
|
||||
<div>
|
||||
{!showMoreFilters && (
|
||||
<Button
|
||||
buttonStyle={ButtonStyleType.SECONDARY_LINK}
|
||||
title="Show More Options"
|
||||
onClick={() => {
|
||||
setShowMoreFilters(true);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{showMoreFilters && (
|
||||
<Button
|
||||
buttonStyle={ButtonStyleType.SECONDARY_LINK}
|
||||
title="Hide More Options"
|
||||
onClick={() => {
|
||||
setShowMoreFilters(false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
{/* {!isSqlQuery && (
|
||||
<Button
|
||||
buttonStyle={
|
||||
ButtonStyleType.SECONDARY_LINK
|
||||
}
|
||||
title="Search with SQL instead"
|
||||
onClick={() => {
|
||||
setIsSqlQuery(true);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{isSqlQuery && (
|
||||
<Button
|
||||
buttonStyle={
|
||||
ButtonStyleType.SECONDARY_LINK
|
||||
}
|
||||
title="Search with Text instead"
|
||||
onClick={() => {
|
||||
setIsSqlQuery(false);
|
||||
}}
|
||||
/>
|
||||
)} */}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex">
|
||||
{/* <div>
|
||||
<Button
|
||||
buttonStyle={ButtonStyleType.SECONDARY_LINK}
|
||||
title="Save as Preset"
|
||||
onClick={() => {
|
||||
setIsSqlQuery(true);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Button
|
||||
buttonStyle={ButtonStyleType.SECONDARY_LINK}
|
||||
title="Load from Preset"
|
||||
onClick={() => {
|
||||
setIsSqlQuery(true);
|
||||
}}
|
||||
/>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LogsFilters;
|
||||
@@ -5,7 +5,8 @@ import FiltersForm from "../Filters/FiltersForm";
|
||||
import FieldType from "../Types/FieldType";
|
||||
import LogItem from "./LogItem";
|
||||
import { PromiseVoidFunction, VoidFunction } from "Common/Types/FunctionTypes";
|
||||
import Log, { LogSeverity } from "Model/AnalyticsModels/Log";
|
||||
import Log from "Model/AnalyticsModels/Log";
|
||||
import LogSeverity from "Common/Types/Log/LogSeverity";
|
||||
import React, { FunctionComponent, ReactElement, Ref } from "react";
|
||||
import Toggle from "../Toggle/Toggle";
|
||||
import Card from "../Card/Card";
|
||||
|
||||
@@ -11,6 +11,7 @@ enum FieldType {
|
||||
Number = "Number",
|
||||
Password = "Password",
|
||||
Dropdown = "Dropdown",
|
||||
MultiSelectDropdown = "MultiSelectDropdown",
|
||||
Text = "Text",
|
||||
Email = "Email",
|
||||
Date = "Date",
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
import LogSeverity from "Common/Types/Log/LogSeverity";
|
||||
import MonitorStepLogMonitor from "Common/Types/Monitor/MonitorStepLogMonitor";
|
||||
import FiltersForm from "CommonUI/src/Components/Filters/FiltersForm";
|
||||
import FieldType from "CommonUI/src/Components/Types/FieldType";
|
||||
import Query from "CommonUI/src/Utils/BaseDatabase/Query";
|
||||
import DropdownUtil from "CommonUI/src/Utils/Dropdown";
|
||||
import TelemetryService from "Model/Models/TelemetryService";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
|
||||
export interface ComponentProps {
|
||||
monitorStepLogMonitor: MonitorStepLogMonitor;
|
||||
onMonitorStepLogMonitorChanged: (
|
||||
monitorStepLogMonitor: MonitorStepLogMonitor,
|
||||
) => void;
|
||||
attributeKeys: Array<string>;
|
||||
telemetryServices: Array<TelemetryService>;
|
||||
}
|
||||
|
||||
const LogMonitorStepForm: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
): ReactElement => {
|
||||
return (
|
||||
<FiltersForm<MonitorStepLogMonitor>
|
||||
id="logs-filter"
|
||||
showFilter={true}
|
||||
filterData={props.monitorStepLogMonitor}
|
||||
onFilterChanged={(filterData: Query<MonitorStepLogMonitor>) => {
|
||||
props.onMonitorStepLogMonitorChanged(
|
||||
filterData as MonitorStepLogMonitor,
|
||||
);
|
||||
}}
|
||||
filters={[
|
||||
{
|
||||
key: "body",
|
||||
type: FieldType.Text,
|
||||
title: "Search Log Body",
|
||||
},
|
||||
{
|
||||
key: "lastXSecondsOfLogs",
|
||||
type: FieldType.Dropdown,
|
||||
filterDropdownOptions: [
|
||||
{
|
||||
label: "Last 5 seconds",
|
||||
value: 5,
|
||||
},
|
||||
{
|
||||
label: "Last 10 seconds",
|
||||
value: 10,
|
||||
},
|
||||
{
|
||||
label: "Last 30 seconds",
|
||||
value: 30,
|
||||
},
|
||||
{
|
||||
label: "Last 1 minute",
|
||||
value: 60,
|
||||
},
|
||||
{
|
||||
label: "Last 5 minutes",
|
||||
value: 300,
|
||||
},
|
||||
{
|
||||
label: "Last 15 minutes",
|
||||
value: 900,
|
||||
},
|
||||
{
|
||||
label: "Last 30 minutes",
|
||||
value: 1800,
|
||||
},
|
||||
{
|
||||
label: "Last 1 hour",
|
||||
value: 3600,
|
||||
},
|
||||
{
|
||||
label: "Last 6 hours",
|
||||
value: 21600,
|
||||
},
|
||||
{
|
||||
label: "Last 12 hours",
|
||||
value: 43200,
|
||||
},
|
||||
{
|
||||
label: "Last 24 hours",
|
||||
value: 86400,
|
||||
},
|
||||
],
|
||||
title: "Check Last X Seconds of Logs",
|
||||
isAdvancedFilter: true,
|
||||
},
|
||||
{
|
||||
key: "severityText",
|
||||
filterDropdownOptions:
|
||||
DropdownUtil.getDropdownOptionsFromEnum(LogSeverity),
|
||||
type: FieldType.MultiSelectDropdown,
|
||||
title: "Log Severity",
|
||||
isAdvancedFilter: true,
|
||||
},
|
||||
{
|
||||
key: "telemetryServiceId",
|
||||
type: FieldType.MultiSelectDropdown,
|
||||
filterDropdownOptions: props.telemetryServices.map(
|
||||
(telemetryService: TelemetryService) => {
|
||||
return {
|
||||
label: telemetryService.name!,
|
||||
value: telemetryService.id?.toString() || "",
|
||||
};
|
||||
},
|
||||
),
|
||||
title: "Filter by Telemetry Service",
|
||||
isAdvancedFilter: true,
|
||||
},
|
||||
{
|
||||
key: "attributes",
|
||||
type: FieldType.JSON,
|
||||
title: "Filter by Attributes",
|
||||
jsonKeys: props.attributeKeys,
|
||||
isAdvancedFilter: true,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default LogMonitorStepForm;
|
||||
@@ -8,6 +8,7 @@ import Exception from "Common/Types/Exception/Exception";
|
||||
import IP from "Common/Types/IP/IP";
|
||||
import MonitorCriteria from "Common/Types/Monitor/MonitorCriteria";
|
||||
import MonitorStep from "Common/Types/Monitor/MonitorStep";
|
||||
import MonitorStepLogMonitor, { MonitorStepLogMonitorUtil } from "Common/Types/Monitor/MonitorStepLogMonitor";
|
||||
import MonitorType from "Common/Types/Monitor/MonitorType";
|
||||
import BrowserType from "Common/Types/Monitor/SyntheticMonitors/BrowserType";
|
||||
import Port from "Common/Types/Port";
|
||||
@@ -27,7 +28,7 @@ import FieldLabelElement from "CommonUI/src/Components/Forms/Fields/FieldLabel";
|
||||
import HorizontalRule from "CommonUI/src/Components/HorizontalRule/HorizontalRule";
|
||||
import Input from "CommonUI/src/Components/Input/Input";
|
||||
import Link from "CommonUI/src/Components/Link/Link";
|
||||
import { DOCS_URL } from "CommonUI/src/Config";
|
||||
import { APP_API_URL, DOCS_URL } from "CommonUI/src/Config";
|
||||
import DropdownUtil from "CommonUI/src/Utils/Dropdown";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
@@ -35,6 +36,19 @@ import React, {
|
||||
useEffect,
|
||||
useState,
|
||||
} from "react";
|
||||
import LogMonitorStepForm from "./LogMonitor/LogMonitorStepFrom";
|
||||
import TelemetryService from "Model/Models/TelemetryService";
|
||||
import ModelAPI, { ListResult } from "CommonUI/src/Utils/ModelAPI/ModelAPI";
|
||||
import DashboardNavigation from "../../../Utils/Navigation";
|
||||
import { LIMIT_PER_PROJECT } from "Common/Types/Database/LimitMax";
|
||||
import SortOrder from "Common/Types/BaseDatabase/SortOrder";
|
||||
import HTTPErrorResponse from "Common/Types/API/HTTPErrorResponse";
|
||||
import API from "CommonUI/src/Utils/API/API";
|
||||
import HTTPResponse from "Common/Types/API/HTTPResponse";
|
||||
import { JSONObject } from "Common/Types/JSON";
|
||||
import ComponentLoader from "CommonUI/src/Components/ComponentLoader/ComponentLoader";
|
||||
import ErrorMessage from "CommonUI/src/Components/ErrorMessage/ErrorMessage";
|
||||
import { PromiseVoidFunction } from "Common/Types/FunctionTypes";
|
||||
|
||||
export interface ComponentProps {
|
||||
monitorStatusDropdownOptions: Array<DropdownOption>;
|
||||
@@ -58,12 +72,90 @@ const MonitorStepElement: FunctionComponent<ComponentProps> = (
|
||||
props.initialValue || new MonitorStep(),
|
||||
);
|
||||
|
||||
const [telemetryServices, setTelemetryServices] = useState<
|
||||
Array<TelemetryService>
|
||||
>([]);
|
||||
const [attributeKeys, setAttributeKeys] = useState<Array<string>>([]);
|
||||
const [error, setError] = useState<string>("");
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.onChange && monitorStep) {
|
||||
props.onChange(monitorStep);
|
||||
}
|
||||
}, [monitorStep]);
|
||||
|
||||
const fetchLogAttributes: PromiseVoidFunction = async (): Promise<void> => {
|
||||
const attributeRepsonse: HTTPResponse<JSONObject> | HTTPErrorResponse =
|
||||
await API.post(
|
||||
URL.fromString(APP_API_URL.toString()).addRoute(
|
||||
"/telemetry/logs/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> => {
|
||||
const telemetryServicesResult: ListResult<TelemetryService> =
|
||||
await ModelAPI.getList<TelemetryService>({
|
||||
modelType: TelemetryService,
|
||||
query: {
|
||||
projectId: DashboardNavigation.getProjectId(),
|
||||
},
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
skip: 0,
|
||||
select: {
|
||||
_id: true,
|
||||
name: true,
|
||||
},
|
||||
sort: {
|
||||
name: SortOrder.Ascending,
|
||||
},
|
||||
});
|
||||
|
||||
if (telemetryServicesResult instanceof HTTPErrorResponse) {
|
||||
throw telemetryServicesResult;
|
||||
}
|
||||
|
||||
setTelemetryServices(telemetryServicesResult.data);
|
||||
};
|
||||
|
||||
const fetchTelemetryServicesAndAttributes: PromiseVoidFunction =
|
||||
async (): Promise<void> => {
|
||||
setIsLoading(true);
|
||||
setError("");
|
||||
try {
|
||||
await fetchTelemetryServices();
|
||||
|
||||
if (props.monitorType === MonitorType.Logs) {
|
||||
await fetchLogAttributes();
|
||||
}
|
||||
} catch (err) {
|
||||
setError(API.getFriendlyErrorMessage(err as Error));
|
||||
}
|
||||
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchTelemetryServicesAndAttributes().catch((err: Error) => {
|
||||
setError(API.getFriendlyErrorMessage(err as Error));
|
||||
});
|
||||
}, [props.monitorType]);
|
||||
|
||||
const [errors, setErrors] = useState<Dictionary<string>>({});
|
||||
const [touched, setTouched] = useState<Dictionary<boolean>>({});
|
||||
|
||||
@@ -158,6 +250,14 @@ const MonitorStepElement: FunctionComponent<ComponentProps> = (
|
||||
props.monitorType === MonitorType.CustomJavaScriptCode ||
|
||||
props.monitorType === MonitorType.SyntheticMonitor;
|
||||
|
||||
if (isLoading) {
|
||||
return <ComponentLoader />;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <ErrorMessage error={error} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mt-5">
|
||||
{hasMonitorDestination && (
|
||||
@@ -267,6 +367,29 @@ const MonitorStepElement: FunctionComponent<ComponentProps> = (
|
||||
</div>
|
||||
)}
|
||||
|
||||
{props.monitorType === MonitorType.Logs && (
|
||||
<div className="mt-5">
|
||||
<FieldLabelElement
|
||||
title={"Log Query"}
|
||||
description={
|
||||
"Please select the subset of logs you want to monitor."
|
||||
}
|
||||
required={true}
|
||||
/>
|
||||
<LogMonitorStepForm
|
||||
monitorStepLogMonitor={monitorStep.data?.logMonitor || MonitorStepLogMonitorUtil.getDefault()}
|
||||
onMonitorStepLogMonitorChanged={(
|
||||
value: MonitorStepLogMonitor,
|
||||
) => {
|
||||
monitorStep.setLogMonitor(value);
|
||||
setMonitorStep(MonitorStep.clone(monitorStep));
|
||||
}}
|
||||
attributeKeys={attributeKeys}
|
||||
telemetryServices={telemetryServices}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{props.monitorType === MonitorType.API && (
|
||||
<div className="mt-5">
|
||||
<FieldLabelElement
|
||||
|
||||
@@ -13,7 +13,8 @@ import Express, {
|
||||
} from "CommonServer/Utils/Express";
|
||||
import logger from "CommonServer/Utils/Logger";
|
||||
import Response from "CommonServer/Utils/Response";
|
||||
import Log, { LogSeverity } from "Model/AnalyticsModels/Log";
|
||||
import Log from "Model/AnalyticsModels/Log";
|
||||
import LogSeverity from "Common/Types/Log/LogSeverity";
|
||||
import OTelIngestService from "../Service/OTelIngest";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
import JSONFunctions from "Common/Types/JSONFunctions";
|
||||
|
||||
@@ -24,7 +24,7 @@ import Express, {
|
||||
} from "CommonServer/Utils/Express";
|
||||
import logger from "CommonServer/Utils/Logger";
|
||||
import Response from "CommonServer/Utils/Response";
|
||||
import Log, { LogSeverity } from "Model/AnalyticsModels/Log";
|
||||
import Log, rity } from "Model/AnalyticsModels/Log";
|
||||
import Metric, { MetricPointType } from "Model/AnalyticsModels/Metric";
|
||||
import Span, { SpanKind, SpanStatus } from "Model/AnalyticsModels/Span";
|
||||
import protobuf from "protobufjs";
|
||||
|
||||
@@ -6,16 +6,7 @@ import TableColumnType from "Common/Types/AnalyticsDatabase/TableColumnType";
|
||||
import { JSONObject } from "Common/Types/JSON";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
import Permission from "Common/Types/Permission";
|
||||
|
||||
export enum LogSeverity {
|
||||
Unspecified = "Unspecified",
|
||||
Information = "Information",
|
||||
Warning = "Warning",
|
||||
Error = "Error",
|
||||
Trace = "Trace",
|
||||
Debug = "Debug",
|
||||
Fatal = "Fatal",
|
||||
}
|
||||
import LogSeverity from "Common/Types/Log/LogSeverity";
|
||||
|
||||
export default class Log extends AnalyticsBaseModel {
|
||||
public constructor() {
|
||||
|
||||
Reference in New Issue
Block a user