Skip to content

Commit

Permalink
[Logs Overview] Overview component (iteration 1) (attempt 2) (#195673)
Browse files Browse the repository at this point in the history
This is a re-submission of #191899, which was reverted due to
a storybook build problem. This introduces a "Logs Overview" component for use in solution UIs
behind a feature flag.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Kerry Gallagher <471693+Kerry350@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
4 people authored Oct 10, 2024
1 parent 44a42a7 commit 0caea22
Show file tree
Hide file tree
Showing 76 changed files with 3,415 additions and 56 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,7 @@ module.exports = {
files: [
'x-pack/plugins/observability_solution/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)',
'src/plugins/ai_assistant_management/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)',
'x-pack/packages/observability/logs_overview/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)',
],
rules: {
'@kbn/i18n/strings_should_be_translated_with_i18n': 'warn',
Expand Down
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ x-pack/packages/observability/alerting_test_data @elastic/obs-ux-management-team
x-pack/test/cases_api_integration/common/plugins/observability @elastic/response-ops
x-pack/packages/observability/get_padded_alert_time_range_util @elastic/obs-ux-management-team
x-pack/plugins/observability_solution/observability_logs_explorer @elastic/obs-ux-logs-team
x-pack/packages/observability/logs_overview @elastic/obs-ux-logs-team
x-pack/plugins/observability_solution/observability_onboarding/e2e @elastic/obs-ux-logs-team @elastic/obs-ux-onboarding-team
x-pack/plugins/observability_solution/observability_onboarding @elastic/obs-ux-logs-team @elastic/obs-ux-onboarding-team
x-pack/plugins/observability_solution/observability @elastic/obs-ux-management-team
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
"@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.cd77847.0",
"@types/react": "~18.2.0",
"@types/react-dom": "~18.2.0",
"@xstate5/react/**/xstate": "^5.18.1",
"globby/fast-glob": "^3.2.11"
},
"dependencies": {
Expand Down Expand Up @@ -687,6 +688,7 @@
"@kbn/observability-fixtures-plugin": "link:x-pack/test/cases_api_integration/common/plugins/observability",
"@kbn/observability-get-padded-alert-time-range-util": "link:x-pack/packages/observability/get_padded_alert_time_range_util",
"@kbn/observability-logs-explorer-plugin": "link:x-pack/plugins/observability_solution/observability_logs_explorer",
"@kbn/observability-logs-overview": "link:x-pack/packages/observability/logs_overview",
"@kbn/observability-onboarding-plugin": "link:x-pack/plugins/observability_solution/observability_onboarding",
"@kbn/observability-plugin": "link:x-pack/plugins/observability_solution/observability",
"@kbn/observability-shared-plugin": "link:x-pack/plugins/observability_solution/observability_shared",
Expand Down Expand Up @@ -1050,6 +1052,7 @@
"@turf/helpers": "6.0.1",
"@turf/length": "^6.0.2",
"@xstate/react": "^3.2.2",
"@xstate5/react": "npm:@xstate/react@^4.1.2",
"adm-zip": "^0.5.9",
"ai": "^2.2.33",
"ajv": "^8.12.0",
Expand Down Expand Up @@ -1283,6 +1286,7 @@
"whatwg-fetch": "^3.0.0",
"xml2js": "^0.5.0",
"xstate": "^4.38.2",
"xstate5": "npm:xstate@^5.18.1",
"xterm": "^5.1.0",
"yauzl": "^2.10.0",
"yazl": "^2.5.1",
Expand All @@ -1304,6 +1308,7 @@
"@babel/plugin-proposal-optional-chaining": "^7.21.0",
"@babel/plugin-proposal-private-methods": "^7.18.6",
"@babel/plugin-transform-class-properties": "^7.24.7",
"@babel/plugin-transform-logical-assignment-operators": "^7.24.7",
"@babel/plugin-transform-numeric-separator": "^7.24.7",
"@babel/plugin-transform-runtime": "^7.24.7",
"@babel/preset-env": "^7.24.7",
Expand Down
12 changes: 12 additions & 0 deletions packages/kbn-apm-synthtrace-client/src/lib/entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

export type ObjectEntry<T> = [keyof T, T[keyof T]];

export type Fields<TMeta extends Record<string, any> | undefined = undefined> = {
'@timestamp'?: number;
} & (TMeta extends undefined ? {} : Partial<{ meta: TMeta }>);
Expand All @@ -27,4 +29,14 @@ export class Entity<TFields extends Fields> {

return this;
}

overrides(overrides: Partial<TFields>) {
const overrideEntries = Object.entries(overrides) as Array<ObjectEntry<TFields>>;

overrideEntries.forEach(([fieldName, value]) => {
this.fields[fieldName] = value;
});

return this;
}
}
74 changes: 74 additions & 0 deletions packages/kbn-apm-synthtrace-client/src/lib/gaussian_events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { castArray } from 'lodash';
import { SynthtraceGenerator } from '../types';
import { Fields } from './entity';
import { Serializable } from './serializable';

export class GaussianEvents<TFields extends Fields = Fields> {
constructor(
private readonly from: Date,
private readonly to: Date,
private readonly mean: Date,
private readonly width: number,
private readonly totalPoints: number
) {}

*generator<TGeneratedFields extends Fields = TFields>(
map: (
timestamp: number,
index: number
) => Serializable<TGeneratedFields> | Array<Serializable<TGeneratedFields>>
): SynthtraceGenerator<TGeneratedFields> {
if (this.totalPoints <= 0) {
return;
}

const startTime = this.from.getTime();
const endTime = this.to.getTime();
const meanTime = this.mean.getTime();
const densityInterval = 1 / (this.totalPoints - 1);

for (let eventIndex = 0; eventIndex < this.totalPoints; eventIndex++) {
const quantile = eventIndex * densityInterval;

const standardScore = Math.sqrt(2) * inverseError(2 * quantile - 1);
const timestamp = Math.round(meanTime + standardScore * this.width);

if (timestamp >= startTime && timestamp <= endTime) {
yield* this.generateEvents(timestamp, eventIndex, map);
}
}
}

private *generateEvents<TGeneratedFields extends Fields = TFields>(
timestamp: number,
eventIndex: number,
map: (
timestamp: number,
index: number
) => Serializable<TGeneratedFields> | Array<Serializable<TGeneratedFields>>
): Generator<Serializable<TGeneratedFields>> {
const events = castArray(map(timestamp, eventIndex));
for (const event of events) {
yield event;
}
}
}

function inverseError(x: number): number {
const a = 0.147;
const sign = x < 0 ? -1 : 1;

const part1 = 2 / (Math.PI * a) + Math.log(1 - x * x) / 2;
const part2 = Math.log(1 - x * x) / a;

return sign * Math.sqrt(Math.sqrt(part1 * part1 - part2) - part1);
}
10 changes: 9 additions & 1 deletion packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ interface HostDocument extends Fields {
'cloud.provider'?: string;
}

class Host extends Entity<HostDocument> {
export class Host extends Entity<HostDocument> {
cpu({ cpuTotalValue }: { cpuTotalValue?: number } = {}) {
return new HostMetrics({
...this.fields,
Expand Down Expand Up @@ -175,3 +175,11 @@ export function host(name: string): Host {
'cloud.provider': 'gcp',
});
}

export function minimalHost(name: string): Host {
return new Host({
'agent.id': 'synthtrace',
'host.hostname': name,
'host.name': name,
});
}
3 changes: 2 additions & 1 deletion packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

import { dockerContainer, DockerContainerMetricsDocument } from './docker_container';
import { host, HostMetricsDocument } from './host';
import { host, HostMetricsDocument, minimalHost } from './host';
import { k8sContainer, K8sContainerMetricsDocument } from './k8s_container';
import { pod, PodMetricsDocument } from './pod';
import { awsRds, AWSRdsMetricsDocument } from './aws/rds';
Expand All @@ -24,6 +24,7 @@ export type InfraDocument =

export const infra = {
host,
minimalHost,
pod,
dockerContainer,
k8sContainer,
Expand Down
18 changes: 15 additions & 3 deletions packages/kbn-apm-synthtrace-client/src/lib/interval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ interface IntervalOptions {
rate?: number;
}

interface StepDetails {
stepMilliseconds: number;
}

export class Interval<TFields extends Fields = Fields> {
private readonly intervalAmount: number;
private readonly intervalUnit: unitOfTime.DurationConstructor;
Expand All @@ -46,12 +50,16 @@ export class Interval<TFields extends Fields = Fields> {
this._rate = options.rate || 1;
}

private getIntervalMilliseconds(): number {
return moment.duration(this.intervalAmount, this.intervalUnit).asMilliseconds();
}

private getTimestamps() {
const from = this.options.from.getTime();
const to = this.options.to.getTime();

let time: number = from;
const diff = moment.duration(this.intervalAmount, this.intervalUnit).asMilliseconds();
const diff = this.getIntervalMilliseconds();

const timestamps: number[] = [];

Expand All @@ -68,15 +76,19 @@ export class Interval<TFields extends Fields = Fields> {
*generator<TGeneratedFields extends Fields = TFields>(
map: (
timestamp: number,
index: number
index: number,
stepDetails: StepDetails
) => Serializable<TGeneratedFields> | Array<Serializable<TGeneratedFields>>
): SynthtraceGenerator<TGeneratedFields> {
const timestamps = this.getTimestamps();
const stepDetails: StepDetails = {
stepMilliseconds: this.getIntervalMilliseconds(),
};

let index = 0;

for (const timestamp of timestamps) {
const events = castArray(map(timestamp, index));
const events = castArray(map(timestamp, index, stepDetails));
index++;
for (const event of events) {
yield event;
Expand Down
21 changes: 21 additions & 0 deletions packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export type LogDocument = Fields &
'event.duration': number;
'event.start': Date;
'event.end': Date;
labels?: Record<string, string>;
test_field: string | string[];
date: Date;
severity: string;
Expand Down Expand Up @@ -156,6 +157,26 @@ function create(logsOptions: LogsOptions = defaultLogsOptions): Log {
).dataset('synth');
}

function createMinimal({
dataset = 'synth',
namespace = 'default',
}: {
dataset?: string;
namespace?: string;
} = {}): Log {
return new Log(
{
'input.type': 'logs',
'data_stream.namespace': namespace,
'data_stream.type': 'logs',
'data_stream.dataset': dataset,
'event.dataset': dataset,
},
{ isLogsDb: false }
);
}

export const log = {
create,
createMinimal,
};
53 changes: 53 additions & 0 deletions packages/kbn-apm-synthtrace-client/src/lib/poisson_events.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { PoissonEvents } from './poisson_events';
import { Serializable } from './serializable';

describe('poisson events', () => {
it('generates events within the given time range', () => {
const poissonEvents = new PoissonEvents(new Date(1000), new Date(2000), 10);

const events = Array.from(
poissonEvents.generator((timestamp) => new Serializable({ '@timestamp': timestamp }))
);

expect(events.length).toBeGreaterThanOrEqual(1);

for (const event of events) {
expect(event.fields['@timestamp']).toBeGreaterThanOrEqual(1000);
expect(event.fields['@timestamp']).toBeLessThanOrEqual(2000);
}
});

it('generates at least one event if the rate is greater than 0', () => {
const poissonEvents = new PoissonEvents(new Date(1000), new Date(2000), 1);

const events = Array.from(
poissonEvents.generator((timestamp) => new Serializable({ '@timestamp': timestamp }))
);

expect(events.length).toBeGreaterThanOrEqual(1);

for (const event of events) {
expect(event.fields['@timestamp']).toBeGreaterThanOrEqual(1000);
expect(event.fields['@timestamp']).toBeLessThanOrEqual(2000);
}
});

it('generates no event if the rate is 0', () => {
const poissonEvents = new PoissonEvents(new Date(1000), new Date(2000), 0);

const events = Array.from(
poissonEvents.generator((timestamp) => new Serializable({ '@timestamp': timestamp }))
);

expect(events.length).toBe(0);
});
});
Loading

0 comments on commit 0caea22

Please sign in to comment.