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:
Simon Larsen
2024-08-04 16:41:07 -06:00
parent a49709992c
commit d84cf5b8ec
16 changed files with 372 additions and 296 deletions

View File

@@ -0,0 +1,11 @@
enum LogSeverity {
Unspecified = "Unspecified",
Information = "Information",
Warning = "Warning",
Error = "Error",
Trace = "Trace",
Debug = "Debug",
Fatal = "Fatal",
}
export default LogSeverity;

View File

@@ -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;

View 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,
};
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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}`}
/>
);

View File

@@ -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

View File

@@ -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";

View File

@@ -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;

View File

@@ -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";

View File

@@ -11,6 +11,7 @@ enum FieldType {
Number = "Number",
Password = "Password",
Dropdown = "Dropdown",
MultiSelectDropdown = "MultiSelectDropdown",
Text = "Text",
Email = "Email",
Date = "Date",

View File

@@ -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;

View File

@@ -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

View File

@@ -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";

View File

@@ -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";

View File

@@ -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() {