mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[APM] Mobile most launches (#168925)
## Summary
Enabling the "Most launches" Mobile dashboard panel which shows an
aggregation of log events that contain the attribute
`labels.lifecycle_state` set to either `created` (for Android) or
`active` (for iOS).

### Checklist
Delete any items that are not applicable to this PR.
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
### For maintainers
- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
---------
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Katerina <kate@kpatticha.com>
This commit is contained in:
parent
b56283932a
commit
820cfc02cf
17 changed files with 330 additions and 24 deletions
|
@ -38,6 +38,7 @@ export type ApmUserAgentFields = Partial<{
|
|||
export interface ApmException {
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface Observer {
|
||||
type: string;
|
||||
version: string;
|
||||
|
@ -94,6 +95,7 @@ export type ApmFields = Fields<{
|
|||
'error.type': string;
|
||||
'event.ingested': number;
|
||||
'event.name': string;
|
||||
'event.action': string;
|
||||
'event.outcome': string;
|
||||
'event.outcome_numeric':
|
||||
| number
|
||||
|
@ -121,6 +123,7 @@ export type ApmFields = Fields<{
|
|||
'kubernetes.pod.uid': string;
|
||||
'labels.name': string;
|
||||
'labels.telemetry_auto_version': string;
|
||||
'labels.lifecycle_state': string;
|
||||
'metricset.name': string;
|
||||
'network.carrier.icc': string;
|
||||
'network.carrier.mcc': string;
|
||||
|
|
30
packages/kbn-apm-synthtrace-client/src/lib/apm/event.ts
Normal file
30
packages/kbn-apm-synthtrace-client/src/lib/apm/event.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { ApmFields } from './apm_fields';
|
||||
import { Serializable } from '../serializable';
|
||||
|
||||
export class Event extends Serializable<ApmFields> {
|
||||
constructor(fields: ApmFields) {
|
||||
super({
|
||||
...fields,
|
||||
});
|
||||
}
|
||||
|
||||
lifecycle(state: string): this {
|
||||
this.fields['event.action'] = 'lifecycle';
|
||||
this.fields['labels.lifecycle_state'] = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
override timestamp(timestamp: number) {
|
||||
const ret = super.timestamp(timestamp);
|
||||
this.fields['timestamp.us'] = timestamp * 1000;
|
||||
return ret;
|
||||
}
|
||||
}
|
|
@ -9,7 +9,8 @@
|
|||
import { Entity } from '../entity';
|
||||
import { Span } from './span';
|
||||
import { Transaction } from './transaction';
|
||||
import { ApmFields, SpanParams, GeoLocation, ApmApplicationMetricFields } from './apm_fields';
|
||||
import { Event } from './event';
|
||||
import { ApmApplicationMetricFields, ApmFields, GeoLocation, SpanParams } from './apm_fields';
|
||||
import { generateLongId } from '../utils/generate_id';
|
||||
import { Metricset } from './metricset';
|
||||
import { ApmError } from './apm_error';
|
||||
|
@ -143,6 +144,10 @@ export class MobileDevice extends Entity<ApmFields> {
|
|||
return this;
|
||||
}
|
||||
|
||||
event(): Event {
|
||||
return new Event({ ...this.fields });
|
||||
}
|
||||
|
||||
transaction(
|
||||
...options:
|
||||
| [{ transactionName: string; frameworkName?: string; frameworkVersion?: string }]
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import { ApmError } from './apm_error';
|
||||
import { Event } from './event';
|
||||
import { BaseSpan } from './base_span';
|
||||
import { generateShortId } from '../utils/generate_id';
|
||||
import { ApmFields } from './apm_fields';
|
||||
|
@ -15,6 +16,7 @@ import { getBreakdownMetrics } from './processors/get_breakdown_metrics';
|
|||
export class Transaction extends BaseSpan {
|
||||
private _sampled: boolean = true;
|
||||
private readonly _errors: ApmError[] = [];
|
||||
private readonly _events: Event[] = [];
|
||||
|
||||
constructor(fields: ApmFields) {
|
||||
super({
|
||||
|
@ -35,6 +37,27 @@ export class Transaction extends BaseSpan {
|
|||
error.fields['transaction.sampled'] = this.fields['transaction.sampled'];
|
||||
});
|
||||
|
||||
this._events.forEach((event) => {
|
||||
event.fields['trace.id'] = this.fields['trace.id'];
|
||||
event.fields['transaction.id'] = this.fields['transaction.id'];
|
||||
event.fields['transaction.type'] = this.fields['transaction.type'];
|
||||
event.fields['transaction.sampled'] = this.fields['transaction.sampled'];
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
events(...events: Event[]) {
|
||||
events.forEach((event) => {
|
||||
event.fields['trace.id'] = this.fields['trace.id'];
|
||||
event.fields['transaction.id'] = this.fields['transaction.id'];
|
||||
event.fields['transaction.name'] = this.fields['transaction.name'];
|
||||
event.fields['transaction.type'] = this.fields['transaction.type'];
|
||||
event.fields['transaction.sampled'] = this.fields['transaction.sampled'];
|
||||
});
|
||||
|
||||
this._events.push(...events);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -62,6 +85,9 @@ export class Transaction extends BaseSpan {
|
|||
this._errors.forEach((error) => {
|
||||
error.fields['transaction.sampled'] = sampled;
|
||||
});
|
||||
this._events.forEach((event) => {
|
||||
event.fields['transaction.sampled'] = sampled;
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -69,6 +95,7 @@ export class Transaction extends BaseSpan {
|
|||
const [transaction, ...spans] = super.serialize();
|
||||
|
||||
const errors = this._errors.flatMap((error) => error.serialize());
|
||||
const logEvents = this._events.flatMap((event) => event.serialize());
|
||||
|
||||
const directChildren = this.getChildren().map((child) => child.fields);
|
||||
|
||||
|
@ -80,6 +107,6 @@ export class Transaction extends BaseSpan {
|
|||
events.push(...spans);
|
||||
}
|
||||
|
||||
return events.concat(errors).concat(breakdownMetrics);
|
||||
return events.concat(errors).concat(breakdownMetrics).concat(logEvents);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,11 @@ export function getRoutingTransform() {
|
|||
index = `metrics-apm.internal-${namespace}`;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (document['event.action'] != null) {
|
||||
index = `logs-apm.app-${namespace}`;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!index) {
|
||||
|
|
|
@ -158,6 +158,8 @@ exports[`Error KUBERNETES_REPLICASET_NAME 1`] = `undefined`;
|
|||
|
||||
exports[`Error LABEL_GC 1`] = `undefined`;
|
||||
|
||||
exports[`Error LABEL_LIFECYCLE_STATE 1`] = `undefined`;
|
||||
|
||||
exports[`Error LABEL_NAME 1`] = `undefined`;
|
||||
|
||||
exports[`Error LABEL_TELEMETRY_AUTO_VERSION 1`] = `undefined`;
|
||||
|
@ -485,6 +487,8 @@ exports[`Span KUBERNETES_REPLICASET_NAME 1`] = `undefined`;
|
|||
|
||||
exports[`Span LABEL_GC 1`] = `undefined`;
|
||||
|
||||
exports[`Span LABEL_LIFECYCLE_STATE 1`] = `undefined`;
|
||||
|
||||
exports[`Span LABEL_NAME 1`] = `undefined`;
|
||||
|
||||
exports[`Span LABEL_TELEMETRY_AUTO_VERSION 1`] = `undefined`;
|
||||
|
@ -822,6 +826,8 @@ exports[`Transaction KUBERNETES_REPLICASET_NAME 1`] = `undefined`;
|
|||
|
||||
exports[`Transaction LABEL_GC 1`] = `undefined`;
|
||||
|
||||
exports[`Transaction LABEL_LIFECYCLE_STATE 1`] = `undefined`;
|
||||
|
||||
exports[`Transaction LABEL_NAME 1`] = `undefined`;
|
||||
|
||||
exports[`Transaction LABEL_TELEMETRY_AUTO_VERSION 1`] = `undefined`;
|
||||
|
|
|
@ -140,6 +140,7 @@ export const LABEL_NAME = 'labels.name';
|
|||
export const LABEL_GC = 'labels.gc';
|
||||
export const LABEL_TYPE = 'labels.type';
|
||||
export const LABEL_TELEMETRY_AUTO_VERSION = 'labels.telemetry_auto_version';
|
||||
export const LABEL_LIFECYCLE_STATE = 'labels.lifecycle_state';
|
||||
|
||||
export const HOST = 'host';
|
||||
export const HOST_HOSTNAME = 'host.hostname'; // Do not use. Please use `HOST_NAME` instead.
|
||||
|
|
|
@ -163,17 +163,18 @@ export function MobileLocationStats({
|
|||
trendShape: MetricTrendShape.Area,
|
||||
},
|
||||
{
|
||||
color: euiTheme.eui.euiColorDisabled,
|
||||
color: euiTheme.eui.euiColorLightestShade,
|
||||
title: i18n.translate('xpack.apm.mobile.location.metrics.launches', {
|
||||
defaultMessage: 'Most launches',
|
||||
}),
|
||||
subtitle: i18n.translate('xpack.apm.mobile.coming.soon', {
|
||||
defaultMessage: 'Coming Soon',
|
||||
extra: getComparisonValueFormatter({
|
||||
currentPeriodValue: currentPeriod?.mostLaunches.value,
|
||||
previousPeriodValue: previousPeriod?.mostLaunches.value,
|
||||
}),
|
||||
icon: getIcon('launch'),
|
||||
value: NOT_AVAILABLE_LABEL,
|
||||
value: currentPeriod?.mostLaunches.location ?? NOT_AVAILABLE_LABEL,
|
||||
valueFormatter: (value) => `${value}`,
|
||||
trend: [],
|
||||
trend: currentPeriod?.mostLaunches.timeseries,
|
||||
trendShape: MetricTrendShape.Area,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -10,7 +10,6 @@ import type { APMIndices } from '@kbn/apm-data-access-plugin/server';
|
|||
import { ProcessorEvent } from '@kbn/observability-plugin/common';
|
||||
import { uniq } from 'lodash';
|
||||
import { ApmDataSource } from '../../../../../common/data_source';
|
||||
import {} from '../../../../../common/document_type';
|
||||
import { PROCESSOR_EVENT } from '../../../../../common/es_fields/apm';
|
||||
import {
|
||||
getConfigForDocumentType,
|
||||
|
|
|
@ -11,8 +11,8 @@ import type {
|
|||
FieldCapsResponse,
|
||||
MsearchMultisearchBody,
|
||||
MsearchMultisearchHeader,
|
||||
TermsEnumResponse,
|
||||
TermsEnumRequest,
|
||||
TermsEnumResponse,
|
||||
} from '@elastic/elasticsearch/lib/api/types';
|
||||
import { ElasticsearchClient, KibanaRequest } from '@kbn/core/server';
|
||||
import type { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types';
|
||||
|
@ -26,6 +26,7 @@ import { APMError } from '../../../../../typings/es_schemas/ui/apm_error';
|
|||
import { Metric } from '../../../../../typings/es_schemas/ui/metric';
|
||||
import { Span } from '../../../../../typings/es_schemas/ui/span';
|
||||
import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
|
||||
import { Event } from '../../../../../typings/es_schemas/ui/event';
|
||||
import { withApmSpan } from '../../../../utils/with_apm_span';
|
||||
import {
|
||||
callAsyncWithDebug,
|
||||
|
@ -46,6 +47,13 @@ export type APMEventESSearchRequest = Omit<ESSearchRequest, 'index'> & {
|
|||
};
|
||||
};
|
||||
|
||||
export type APMLogEventESSearchRequest = Omit<ESSearchRequest, 'index'> & {
|
||||
body: {
|
||||
size: number;
|
||||
track_total_hits: boolean | number;
|
||||
};
|
||||
};
|
||||
|
||||
type APMEventWrapper<T> = Omit<T, 'index'> & {
|
||||
apm: { events: ProcessorEvent[] };
|
||||
};
|
||||
|
@ -63,6 +71,9 @@ type TypeOfProcessorEvent<T extends ProcessorEvent> = {
|
|||
metric: Metric;
|
||||
}[T];
|
||||
|
||||
type TypedLogEventSearchResponse<TParams extends APMLogEventESSearchRequest> =
|
||||
InferSearchResponseOf<Event, TParams>;
|
||||
|
||||
type TypedSearchResponse<TParams extends APMEventESSearchRequest> =
|
||||
InferSearchResponseOf<
|
||||
TypeOfProcessorEvent<
|
||||
|
@ -196,6 +207,41 @@ export class APMEventClient {
|
|||
});
|
||||
}
|
||||
|
||||
async logEventSearch<TParams extends APMLogEventESSearchRequest>(
|
||||
operationName: string,
|
||||
params: TParams
|
||||
): Promise<TypedLogEventSearchResponse<TParams>> {
|
||||
// Reusing indices configured for errors since both events and errors are stored as logs.
|
||||
const index = processorEventsToIndex([ProcessorEvent.error], this.indices);
|
||||
|
||||
const searchParams = {
|
||||
...omit(params, 'body'),
|
||||
index,
|
||||
body: {
|
||||
...params.body,
|
||||
query: {
|
||||
bool: {
|
||||
must: compact([params.body.query]),
|
||||
},
|
||||
},
|
||||
},
|
||||
...(this.includeFrozen ? { ignore_throttled: false } : {}),
|
||||
ignore_unavailable: true,
|
||||
preference: 'any',
|
||||
expand_wildcards: ['open' as const, 'hidden' as const],
|
||||
};
|
||||
|
||||
return this.callAsyncWithDebug({
|
||||
cb: (opts) =>
|
||||
this.esClient.search(searchParams, opts) as unknown as Promise<{
|
||||
body: TypedLogEventSearchResponse<TParams>;
|
||||
}>,
|
||||
operationName,
|
||||
params: searchParams,
|
||||
requestType: 'search',
|
||||
});
|
||||
}
|
||||
|
||||
async msearch<TParams extends APMEventESSearchRequest>(
|
||||
operationName: string,
|
||||
...allParams: TParams[]
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
rangeQuery,
|
||||
termQuery,
|
||||
} from '@kbn/observability-plugin/server';
|
||||
import { SERVICE_NAME, ERROR_TYPE } from '../../../common/es_fields/apm';
|
||||
import { ERROR_TYPE, SERVICE_NAME } from '../../../common/es_fields/apm';
|
||||
import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client';
|
||||
import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms';
|
||||
import { getBucketSize } from '../../../common/utils/get_bucket_size';
|
||||
|
@ -101,9 +101,7 @@ export async function getCrashesByLocation({
|
|||
timeseries:
|
||||
response.aggregations?.timeseries?.buckets.map((bucket) => ({
|
||||
x: bucket.key,
|
||||
y:
|
||||
response.aggregations?.crashes?.crashesByLocation?.buckets[0]
|
||||
?.doc_count ?? 0,
|
||||
y: bucket?.crashes?.crashesByLocation?.buckets[0]?.doc_count ?? 0,
|
||||
})) ?? [],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,15 +6,15 @@
|
|||
*/
|
||||
|
||||
import {
|
||||
termQuery,
|
||||
kqlQuery,
|
||||
rangeQuery,
|
||||
termQuery,
|
||||
} from '@kbn/observability-plugin/server';
|
||||
import { ProcessorEvent } from '@kbn/observability-plugin/common';
|
||||
import {
|
||||
SERVICE_NAME,
|
||||
SPAN_TYPE,
|
||||
SPAN_SUBTYPE,
|
||||
SPAN_TYPE,
|
||||
} from '../../../common/es_fields/apm';
|
||||
import { environmentQuery } from '../../../common/utils/environment_query';
|
||||
import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client';
|
||||
|
@ -111,9 +111,7 @@ export async function getHttpRequestsByLocation({
|
|||
timeseries:
|
||||
response.aggregations?.timeseries?.buckets.map((bucket) => ({
|
||||
x: bucket.key,
|
||||
y:
|
||||
response.aggregations?.requests?.requestsByLocation?.buckets[0]
|
||||
?.doc_count ?? 0,
|
||||
y: bucket?.requests?.requestsByLocation?.buckets[0]?.doc_count ?? 0,
|
||||
})) ?? [],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
kqlQuery,
|
||||
rangeQuery,
|
||||
termQuery,
|
||||
} from '@kbn/observability-plugin/server';
|
||||
import {
|
||||
LABEL_LIFECYCLE_STATE,
|
||||
SERVICE_NAME,
|
||||
} from '../../../common/es_fields/apm';
|
||||
import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client';
|
||||
import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms';
|
||||
import { getBucketSize } from '../../../common/utils/get_bucket_size';
|
||||
import { environmentQuery } from '../../../common/utils/environment_query';
|
||||
|
||||
interface Props {
|
||||
kuery: string;
|
||||
apmEventClient: APMEventClient;
|
||||
serviceName: string;
|
||||
environment: string;
|
||||
start: number;
|
||||
end: number;
|
||||
locationField?: string;
|
||||
offset?: string;
|
||||
}
|
||||
|
||||
export async function getLaunchesByLocation({
|
||||
kuery,
|
||||
apmEventClient,
|
||||
serviceName,
|
||||
environment,
|
||||
start,
|
||||
end,
|
||||
locationField,
|
||||
offset,
|
||||
}: Props) {
|
||||
const { startWithOffset, endWithOffset } = getOffsetInMs({
|
||||
start,
|
||||
end,
|
||||
offset,
|
||||
});
|
||||
|
||||
const { intervalString } = getBucketSize({
|
||||
start: startWithOffset,
|
||||
end: endWithOffset,
|
||||
minBucketSize: 60,
|
||||
});
|
||||
|
||||
const aggs = {
|
||||
launches: {
|
||||
filter: {
|
||||
terms: { [LABEL_LIFECYCLE_STATE]: ['created', 'active'] },
|
||||
},
|
||||
aggs: {
|
||||
byLocation: {
|
||||
terms: {
|
||||
field: locationField,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const response = await apmEventClient.logEventSearch(
|
||||
'get_mobile_location_launches',
|
||||
{
|
||||
body: {
|
||||
track_total_hits: false,
|
||||
size: 0,
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
...termQuery(SERVICE_NAME, serviceName),
|
||||
...rangeQuery(startWithOffset, endWithOffset),
|
||||
...environmentQuery(environment),
|
||||
...kqlQuery(kuery),
|
||||
],
|
||||
},
|
||||
},
|
||||
aggs: {
|
||||
timeseries: {
|
||||
date_histogram: {
|
||||
field: '@timestamp',
|
||||
fixed_interval: intervalString,
|
||||
min_doc_count: 0,
|
||||
},
|
||||
aggs,
|
||||
},
|
||||
...aggs,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
location: response.aggregations?.launches?.byLocation?.buckets[0]
|
||||
?.key as string,
|
||||
value:
|
||||
response.aggregations?.launches?.byLocation?.buckets[0]?.doc_count ?? 0,
|
||||
timeseries:
|
||||
response.aggregations?.timeseries?.buckets.map((bucket) => ({
|
||||
x: bucket.key,
|
||||
y: bucket.launches?.byLocation?.buckets[0]?.doc_count ?? 0,
|
||||
})) ?? [],
|
||||
};
|
||||
}
|
|
@ -10,6 +10,7 @@ import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_ev
|
|||
import { getSessionsByLocation } from './get_mobile_sessions_by_location';
|
||||
import { getHttpRequestsByLocation } from './get_mobile_http_requests_by_location';
|
||||
import { getCrashesByLocation } from './get_mobile_crashes_by_location';
|
||||
import { getLaunchesByLocation } from './get_mobile_launches_by_location';
|
||||
import { Maybe } from '../../../typings/common';
|
||||
|
||||
export type Timeseries = Array<{ x: number; y: number }>;
|
||||
|
@ -30,6 +31,11 @@ interface LocationStats {
|
|||
value: Maybe<number>;
|
||||
timeseries: Timeseries;
|
||||
};
|
||||
mostLaunches: {
|
||||
location?: string;
|
||||
value: Maybe<number>;
|
||||
timeseries: Timeseries;
|
||||
};
|
||||
}
|
||||
|
||||
export interface MobileLocationStats {
|
||||
|
@ -69,16 +75,19 @@ async function getMobileLocationStats({
|
|||
offset,
|
||||
};
|
||||
|
||||
const [mostSessions, mostRequests, mostCrashes] = await Promise.all([
|
||||
getSessionsByLocation({ ...commonProps }),
|
||||
getHttpRequestsByLocation({ ...commonProps }),
|
||||
getCrashesByLocation({ ...commonProps }),
|
||||
]);
|
||||
const [mostSessions, mostRequests, mostCrashes, mostLaunches] =
|
||||
await Promise.all([
|
||||
getSessionsByLocation({ ...commonProps }),
|
||||
getHttpRequestsByLocation({ ...commonProps }),
|
||||
getCrashesByLocation({ ...commonProps }),
|
||||
getLaunchesByLocation({ ...commonProps }),
|
||||
]);
|
||||
|
||||
return {
|
||||
mostSessions,
|
||||
mostRequests,
|
||||
mostCrashes,
|
||||
mostLaunches,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -117,6 +126,7 @@ export async function getMobileLocationStatsPeriods({
|
|||
mostSessions: { value: null, timeseries: [] },
|
||||
mostRequests: { value: null, timeseries: [] },
|
||||
mostCrashes: { value: null, timeseries: [] },
|
||||
mostLaunches: { value: null, timeseries: [] },
|
||||
};
|
||||
|
||||
const [currentPeriod, previousPeriod] = await Promise.all([
|
||||
|
|
25
x-pack/plugins/apm/typings/es_schemas/raw/event_raw.ts
Normal file
25
x-pack/plugins/apm/typings/es_schemas/raw/event_raw.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { APMBaseDoc } from './apm_base_doc';
|
||||
import { TimestampUs } from './fields/timestamp_us';
|
||||
|
||||
export interface EventRaw extends APMBaseDoc {
|
||||
timestamp: TimestampUs;
|
||||
transaction?: {
|
||||
id: string;
|
||||
sampled?: boolean;
|
||||
type: string;
|
||||
};
|
||||
log: {
|
||||
message?: string;
|
||||
};
|
||||
event: {
|
||||
action: string;
|
||||
category: string;
|
||||
};
|
||||
}
|
13
x-pack/plugins/apm/typings/es_schemas/ui/event.ts
Normal file
13
x-pack/plugins/apm/typings/es_schemas/ui/event.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EventRaw } from '../raw/event_raw';
|
||||
import { Agent } from './fields/agent';
|
||||
|
||||
export interface Event extends EventRaw {
|
||||
agent: Agent;
|
||||
}
|
|
@ -130,7 +130,7 @@ async function generateData({
|
|||
carrierMCC: '440',
|
||||
});
|
||||
|
||||
return await synthtraceEsClient.index([
|
||||
await synthtraceEsClient.index([
|
||||
timerange(start, end)
|
||||
.interval('5m')
|
||||
.rate(1)
|
||||
|
@ -142,6 +142,7 @@ async function generateData({
|
|||
galaxy10
|
||||
.transaction('Start View - View Appearing', 'Android Activity')
|
||||
.errors(galaxy10.crash({ message: 'error' }).timestamp(timestamp))
|
||||
.events(galaxy10.event().lifecycle('created').timestamp(timestamp))
|
||||
.timestamp(timestamp)
|
||||
.duration(500)
|
||||
.success()
|
||||
|
@ -159,12 +160,14 @@ async function generateData({
|
|||
galaxy7
|
||||
.transaction('Start View - View Appearing', 'Android Activity')
|
||||
.errors(galaxy7.crash({ message: 'error' }).timestamp(timestamp))
|
||||
.events(galaxy7.event().lifecycle('created').timestamp(timestamp))
|
||||
.timestamp(timestamp)
|
||||
.duration(20)
|
||||
.success(),
|
||||
huaweiP2
|
||||
.transaction('Start View - View Appearing', 'huaweiP2 Activity')
|
||||
.errors(huaweiP2.crash({ message: 'error' }).timestamp(timestamp))
|
||||
.events(huaweiP2.event().lifecycle('created').timestamp(timestamp))
|
||||
.timestamp(timestamp)
|
||||
.duration(20)
|
||||
.success(),
|
||||
|
@ -222,6 +225,9 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
expect(response.currentPeriod.mostCrashes.timeseries.every((item) => item.y === 0)).to.eql(
|
||||
true
|
||||
);
|
||||
expect(response.currentPeriod.mostLaunches.timeseries.every((item) => item.y === 0)).to.eql(
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -261,6 +267,11 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
const { location } = response.currentPeriod.mostCrashes;
|
||||
expect(location).to.be('China');
|
||||
});
|
||||
|
||||
it('returns location for most launches', () => {
|
||||
const { location } = response.currentPeriod.mostLaunches;
|
||||
expect(location).to.be('China');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when filters are applied', () => {
|
||||
|
@ -274,6 +285,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
expect(response.currentPeriod.mostSessions.value).to.eql(0);
|
||||
expect(response.currentPeriod.mostRequests.value).to.eql(0);
|
||||
expect(response.currentPeriod.mostCrashes.value).to.eql(0);
|
||||
expect(response.currentPeriod.mostLaunches.value).to.eql(0);
|
||||
|
||||
expect(response.currentPeriod.mostSessions.timeseries.every((item) => item.y === 0)).to.eql(
|
||||
true
|
||||
|
@ -284,6 +296,9 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
expect(response.currentPeriod.mostCrashes.timeseries.every((item) => item.y === 0)).to.eql(
|
||||
true
|
||||
);
|
||||
expect(response.currentPeriod.mostLaunches.timeseries.every((item) => item.y === 0)).to.eql(
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('returns the correct values when single filter is applied', async () => {
|
||||
|
@ -293,9 +308,15 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
kuery: `service.version:"1.1"`,
|
||||
});
|
||||
|
||||
expect(response.currentPeriod.mostSessions.timeseries[0].y).to.eql(1);
|
||||
expect(response.currentPeriod.mostCrashes.timeseries[0].y).to.eql(1);
|
||||
expect(response.currentPeriod.mostRequests.timeseries[0].y).to.eql(1);
|
||||
expect(response.currentPeriod.mostLaunches.timeseries[0].y).to.eql(1);
|
||||
|
||||
expect(response.currentPeriod.mostSessions.value).to.eql(3);
|
||||
expect(response.currentPeriod.mostRequests.value).to.eql(3);
|
||||
expect(response.currentPeriod.mostCrashes.value).to.eql(3);
|
||||
expect(response.currentPeriod.mostLaunches.value).to.eql(3);
|
||||
});
|
||||
|
||||
it('returns the correct values when multiple filters are applied', async () => {
|
||||
|
@ -304,9 +325,15 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
kuery: `service.version:"1.1" and service.environment: "production"`,
|
||||
});
|
||||
|
||||
expect(response.currentPeriod.mostSessions.timeseries[0].y).to.eql(1);
|
||||
expect(response.currentPeriod.mostCrashes.timeseries[0].y).to.eql(1);
|
||||
expect(response.currentPeriod.mostRequests.timeseries[0].y).to.eql(1);
|
||||
expect(response.currentPeriod.mostLaunches.timeseries[0].y).to.eql(1);
|
||||
|
||||
expect(response.currentPeriod.mostSessions.value).to.eql(3);
|
||||
expect(response.currentPeriod.mostRequests.value).to.eql(3);
|
||||
expect(response.currentPeriod.mostCrashes.value).to.eql(3);
|
||||
expect(response.currentPeriod.mostLaunches.value).to.eql(3);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue