mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Added mobile synthtrace scenario (#146985)
Extended APM synthtrace to support mobile use cases and added a mobile scenario that generates trace data. Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kate Patticha <aikaterini.patticha@elastic.co>
This commit is contained in:
parent
bc9ee32e3d
commit
6872f82a52
8 changed files with 768 additions and 23 deletions
|
@ -41,14 +41,37 @@ export interface Observer {
|
|||
version_major: number;
|
||||
}
|
||||
|
||||
export interface GeoLocation {
|
||||
coordinates: number[];
|
||||
type: string;
|
||||
}
|
||||
|
||||
export type ApmFields = Fields &
|
||||
Partial<{
|
||||
'timestamp.us'?: number;
|
||||
'agent.name': string;
|
||||
'agent.version': string;
|
||||
'client.geo.city_name': string;
|
||||
'client.geo.continent_name': string;
|
||||
'client.geo.country_iso_code': string;
|
||||
'client.geo.country_name': string;
|
||||
'client.geo.region_iso_code': string;
|
||||
'client.geo.region_name': string;
|
||||
'client.geo.location': GeoLocation;
|
||||
'client.ip': string;
|
||||
'cloud.provider': string;
|
||||
'cloud.project.name': string;
|
||||
'cloud.service.name': string;
|
||||
'cloud.availability_zone': string;
|
||||
'cloud.machine.type': string;
|
||||
'cloud.region': string;
|
||||
'container.id': string;
|
||||
'destination.address': string;
|
||||
'destination.port': number;
|
||||
'device.id': string;
|
||||
'device.model.identifier': string;
|
||||
'device.model.name': string;
|
||||
'device.manufacturer': string;
|
||||
'ecs.version': string;
|
||||
'event.outcome': string;
|
||||
'event.ingested': number;
|
||||
|
@ -56,18 +79,36 @@ export type ApmFields = Fields &
|
|||
'error.exception': ApmException[];
|
||||
'error.grouping_name': string;
|
||||
'error.grouping_key': string;
|
||||
'faas.id': string;
|
||||
'faas.name': string;
|
||||
'faas.coldstart': boolean;
|
||||
'faas.execution': string;
|
||||
'faas.trigger.type': string;
|
||||
'faas.trigger.request_id': string;
|
||||
'host.name': string;
|
||||
'host.architecture': string;
|
||||
'host.hostname': string;
|
||||
'host.os.full': string;
|
||||
'host.os.name': string;
|
||||
'host.os.platform': string;
|
||||
'host.os.type': string;
|
||||
'host.os.version': string;
|
||||
'http.request.method': string;
|
||||
'http.response.status_code': number;
|
||||
'kubernetes.pod.uid': string;
|
||||
'kubernetes.pod.name': string;
|
||||
'metricset.name': string;
|
||||
observer: Observer;
|
||||
'network.connection.type': string;
|
||||
'network.connection.subtype': string;
|
||||
'network.carrier.name': string;
|
||||
'network.carrier.mcc': string;
|
||||
'network.carrier.mnc': string;
|
||||
'network.carrier.icc': string;
|
||||
'parent.id': string;
|
||||
'processor.event': string;
|
||||
'processor.name': string;
|
||||
'session.id': string;
|
||||
'trace.id': string;
|
||||
'transaction.name': string;
|
||||
'transaction.type': string;
|
||||
|
@ -86,6 +127,7 @@ export type ApmFields = Fields &
|
|||
'service.runtime.name': string;
|
||||
'service.runtime.version': string;
|
||||
'service.framework.name': string;
|
||||
'service.framework.version': string;
|
||||
'service.target.name': string;
|
||||
'service.target.type': string;
|
||||
'span.action': string;
|
||||
|
@ -103,18 +145,12 @@ export type ApmFields = Fields &
|
|||
trace: { id: string };
|
||||
span: { id: string };
|
||||
}>;
|
||||
'cloud.provider': string;
|
||||
'cloud.project.name': string;
|
||||
'cloud.service.name': string;
|
||||
'cloud.availability_zone': string;
|
||||
'cloud.machine.type': string;
|
||||
'cloud.region': string;
|
||||
'host.os.platform': string;
|
||||
'faas.id': string;
|
||||
'faas.name': string;
|
||||
'faas.coldstart': boolean;
|
||||
'faas.execution': string;
|
||||
'faas.trigger.type': string;
|
||||
'faas.trigger.request_id': string;
|
||||
'url.original': string;
|
||||
}> &
|
||||
ApmApplicationMetricFields;
|
||||
|
||||
export type SpanParams = {
|
||||
spanName: string;
|
||||
spanType: string;
|
||||
spanSubtype?: string;
|
||||
} & ApmFields;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
import { service } from './service';
|
||||
import { mobileApp } from './mobile_app';
|
||||
import { browser } from './browser';
|
||||
import { serverlessFunction } from './serverless_function';
|
||||
import { getTransactionMetrics } from './processors/get_transaction_metrics';
|
||||
|
@ -20,6 +21,7 @@ import type { ApmException } from './apm_fields';
|
|||
|
||||
export const apm = {
|
||||
service,
|
||||
mobileApp,
|
||||
browser,
|
||||
getTransactionMetrics,
|
||||
getSpanDestinationMetrics,
|
||||
|
|
|
@ -11,13 +11,7 @@ import { Entity } from '../entity';
|
|||
import { Metricset } from './metricset';
|
||||
import { Span } from './span';
|
||||
import { Transaction } from './transaction';
|
||||
import { ApmApplicationMetricFields, ApmFields } from './apm_fields';
|
||||
|
||||
export type SpanParams = {
|
||||
spanName: string;
|
||||
spanType: string;
|
||||
spanSubtype?: string;
|
||||
} & ApmFields;
|
||||
import { ApmApplicationMetricFields, ApmFields, SpanParams } from './apm_fields';
|
||||
|
||||
export class Instance extends Entity<ApmFields> {
|
||||
transaction(
|
||||
|
|
48
packages/kbn-apm-synthtrace/src/lib/apm/mobile_app.ts
Normal file
48
packages/kbn-apm-synthtrace/src/lib/apm/mobile_app.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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 { Entity } from '../entity';
|
||||
import { ApmFields } from './apm_fields';
|
||||
import { MobileDevice } from './mobile_device';
|
||||
import { generateLongId } from '../utils/generate_id';
|
||||
|
||||
type MobileAgentName = 'android/java' | 'iOS/swift';
|
||||
|
||||
export class MobileApp extends Entity<ApmFields> {
|
||||
mobileDevice(deviceId?: string) {
|
||||
return new MobileDevice({
|
||||
...this.fields,
|
||||
'device.id': deviceId ? deviceId : generateLongId(),
|
||||
'service.language.name': this.fields['agent.name'] === 'iOS' ? 'swift' : 'java',
|
||||
'service.version': this.fields['service.version'] ?? '1.0',
|
||||
}).startNewSession();
|
||||
}
|
||||
}
|
||||
|
||||
export function mobileApp(name: string, environment: string, agentName: MobileAgentName): MobileApp;
|
||||
|
||||
export function mobileApp(options: {
|
||||
name: string;
|
||||
environment: string;
|
||||
agentName: MobileAgentName;
|
||||
}): MobileApp;
|
||||
|
||||
export function mobileApp(
|
||||
...args:
|
||||
| [{ name: string; environment: string; agentName: MobileAgentName }]
|
||||
| [string, string, MobileAgentName]
|
||||
) {
|
||||
const [name, environment, agentName] =
|
||||
args.length === 1 ? [args[0].name, args[0].environment, args[0].agentName] : args;
|
||||
|
||||
return new MobileApp({
|
||||
'service.name': name,
|
||||
'service.environment': environment,
|
||||
'agent.name': agentName,
|
||||
});
|
||||
}
|
240
packages/kbn-apm-synthtrace/src/lib/apm/mobile_device.ts
Normal file
240
packages/kbn-apm-synthtrace/src/lib/apm/mobile_device.ts
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* 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 { Entity } from '../entity';
|
||||
import { Span } from './span';
|
||||
import { Transaction } from './transaction';
|
||||
import { ApmFields, SpanParams, GeoLocation } from './apm_fields';
|
||||
import { generateLongId } from '../utils/generate_id';
|
||||
|
||||
export interface DeviceInfo {
|
||||
manufacturer: string;
|
||||
modelIdentifier: string;
|
||||
modelName?: string;
|
||||
}
|
||||
|
||||
export interface OSInfo {
|
||||
osType: 'ios' | 'android';
|
||||
osVersion: string;
|
||||
osFull?: string;
|
||||
runtimeVersion?: string;
|
||||
}
|
||||
|
||||
export interface NetworkConnectionInfo {
|
||||
type: 'unavailable' | 'wifi' | 'wired' | 'cell' | 'unknown';
|
||||
subType?: string;
|
||||
carrierName?: string;
|
||||
carrierMCC?: string;
|
||||
carrierMNC?: string;
|
||||
carrierICC?: string;
|
||||
}
|
||||
|
||||
export interface GeoInfo {
|
||||
clientIp: string;
|
||||
cityName?: string;
|
||||
continentName?: string;
|
||||
countryIsoCode?: string;
|
||||
countryName?: string;
|
||||
regionName?: string;
|
||||
regionIsoCode?: string;
|
||||
location?: GeoLocation;
|
||||
}
|
||||
|
||||
export class MobileDevice extends Entity<ApmFields> {
|
||||
networkConnection: NetworkConnectionInfo;
|
||||
|
||||
constructor(public readonly fields: ApmFields) {
|
||||
super(fields);
|
||||
this.networkConnection = { type: 'unavailable' };
|
||||
}
|
||||
|
||||
deviceInfo(...options: [DeviceInfo] | [string, string] | [string, string, string]) {
|
||||
let manufacturer: string;
|
||||
let modelIdentifier: string;
|
||||
let modelName: string | undefined;
|
||||
if (options.length === 3) {
|
||||
manufacturer = options[0];
|
||||
modelIdentifier = options[1];
|
||||
modelName = options[2];
|
||||
} else if (options.length === 2) {
|
||||
manufacturer = options[0];
|
||||
modelIdentifier = options[1];
|
||||
} else {
|
||||
manufacturer = options[0].manufacturer;
|
||||
modelIdentifier = options[0].modelIdentifier;
|
||||
modelName = options[0].modelName;
|
||||
}
|
||||
|
||||
this.fields['device.manufacturer'] = manufacturer;
|
||||
this.fields['device.model.identifier'] = modelIdentifier;
|
||||
this.fields['device.model.name'] = modelName;
|
||||
return this;
|
||||
}
|
||||
|
||||
osInfo(
|
||||
...options:
|
||||
| [OSInfo]
|
||||
| [string, string]
|
||||
| [string, string, string]
|
||||
| [string, string, string, string]
|
||||
) {
|
||||
let osType: string;
|
||||
let osVersion: string;
|
||||
let osFull: string | undefined;
|
||||
let runtimeVersion: string | undefined;
|
||||
if (options.length === 4) {
|
||||
osType = options[0];
|
||||
osVersion = options[1];
|
||||
osFull = options[2];
|
||||
runtimeVersion = options[3];
|
||||
} else if (options.length === 3) {
|
||||
osType = options[0];
|
||||
osVersion = options[1];
|
||||
osFull = options[2];
|
||||
} else if (options.length === 2) {
|
||||
osType = options[0];
|
||||
osVersion = options[1];
|
||||
} else {
|
||||
osType = options[0].osType;
|
||||
osVersion = options[0].osVersion;
|
||||
osFull = options[0].osFull;
|
||||
runtimeVersion = options[0].runtimeVersion;
|
||||
}
|
||||
|
||||
this.fields['host.os.type'] = osType;
|
||||
this.fields['host.os.name'] = osType === 'ios' ? 'iOS' : 'Android';
|
||||
this.fields['host.os.version'] = osVersion;
|
||||
this.fields['host.os.full'] = osFull;
|
||||
this.fields['service.runtime.name'] = osType === 'ios' ? 'iOS' : 'Android Runtime';
|
||||
this.fields['service.runtime.version'] = runtimeVersion ?? osVersion;
|
||||
return this;
|
||||
}
|
||||
|
||||
startNewSession() {
|
||||
this.fields['session.id'] = generateLongId();
|
||||
return this;
|
||||
}
|
||||
|
||||
setNetworkConnection(networkInfo: NetworkConnectionInfo) {
|
||||
this.networkConnection = networkInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
setGeoInfo(geoInfo: GeoInfo) {
|
||||
if (geoInfo) {
|
||||
this.fields['client.ip'] = geoInfo.clientIp;
|
||||
this.fields['client.geo.city_name'] = geoInfo.cityName;
|
||||
this.fields['client.geo.country_name'] = geoInfo.countryName;
|
||||
this.fields['client.geo.country_iso_code'] = geoInfo.countryIsoCode;
|
||||
this.fields['client.geo.continent_name'] = geoInfo.continentName;
|
||||
this.fields['client.geo.region_name'] = geoInfo.regionName;
|
||||
this.fields['client.geo.region_iso_code'] = geoInfo.regionIsoCode;
|
||||
this.fields['client.geo.location'] = geoInfo.location;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
transaction(
|
||||
...options:
|
||||
| [{ transactionName: string; frameworkName?: string; frameworkVersion?: string }]
|
||||
| [string]
|
||||
| [string, string]
|
||||
| [string, string, string]
|
||||
) {
|
||||
let transactionName: string;
|
||||
let frameworkName: string | undefined;
|
||||
let frameworkVersion: string | undefined;
|
||||
if (options.length === 3) {
|
||||
transactionName = options[0];
|
||||
frameworkName = options[1];
|
||||
frameworkVersion = options[2];
|
||||
} else if (options.length === 2) {
|
||||
transactionName = options[0];
|
||||
frameworkName = options[1];
|
||||
} else if (typeof options[0] === 'string') {
|
||||
transactionName = options[0];
|
||||
} else {
|
||||
transactionName = options[0].transactionName;
|
||||
frameworkName = options[0].frameworkName;
|
||||
frameworkVersion = options[0].frameworkVersion;
|
||||
}
|
||||
return new Transaction({
|
||||
...this.fields,
|
||||
'transaction.name': transactionName,
|
||||
'transaction.type': 'mobile',
|
||||
'service.framework.name': frameworkName,
|
||||
'service.framework.version': frameworkVersion,
|
||||
});
|
||||
}
|
||||
|
||||
span(...options: [string, string] | [string, string, string] | [SpanParams]) {
|
||||
let spanName: string;
|
||||
let spanType: string;
|
||||
let spanSubtype: string;
|
||||
let fields: ApmFields;
|
||||
|
||||
if (options.length === 3 || options.length === 2) {
|
||||
spanName = options[0];
|
||||
spanType = options[1];
|
||||
spanSubtype = options[2] || 'unknown';
|
||||
fields = {};
|
||||
} else {
|
||||
({ spanName, spanType, spanSubtype = 'unknown', ...fields } = options[0]);
|
||||
}
|
||||
|
||||
return new Span({
|
||||
...this.fields,
|
||||
...fields,
|
||||
'span.name': spanName,
|
||||
'span.type': spanType,
|
||||
'span.subtype': spanSubtype,
|
||||
});
|
||||
}
|
||||
|
||||
httpSpan(
|
||||
...options:
|
||||
| [{ spanName: string; httpMethod: string; httpUrl: string }]
|
||||
| [string, string, string]
|
||||
) {
|
||||
let spanName: string;
|
||||
let httpMethod: string;
|
||||
let httpUrl: string;
|
||||
if (options.length === 3) {
|
||||
spanName = options[0];
|
||||
httpMethod = options[1];
|
||||
httpUrl = options[2];
|
||||
} else {
|
||||
spanName = options[0].spanName;
|
||||
httpMethod = options[0].httpMethod;
|
||||
httpUrl = options[0].httpUrl;
|
||||
}
|
||||
|
||||
let spanParameters: SpanParams = {
|
||||
spanName,
|
||||
spanType: 'external',
|
||||
spanSubtype: 'http',
|
||||
'http.request.method': httpMethod,
|
||||
'url.original': httpUrl,
|
||||
};
|
||||
|
||||
if (this.networkConnection) {
|
||||
spanParameters = {
|
||||
...spanParameters,
|
||||
'network.connection.type': this.networkConnection.type,
|
||||
'network.connection.subtype': this.networkConnection.subType,
|
||||
'network.carrier.name': this.networkConnection.carrierName,
|
||||
'network.carrier.mcc': this.networkConnection.carrierMCC,
|
||||
'network.carrier.mnc': this.networkConnection.carrierMNC,
|
||||
'network.carrier.icc': this.networkConnection.carrierICC,
|
||||
};
|
||||
}
|
||||
|
||||
return this.span(spanParameters);
|
||||
}
|
||||
}
|
|
@ -9,8 +9,7 @@
|
|||
import url from 'url';
|
||||
import { BaseSpan } from './base_span';
|
||||
import { generateShortId } from '../utils/generate_id';
|
||||
import { ApmFields } from './apm_fields';
|
||||
import { SpanParams } from './instance';
|
||||
import { ApmFields, SpanParams } from './apm_fields';
|
||||
|
||||
export class Span extends BaseSpan {
|
||||
constructor(fields: ApmFields) {
|
||||
|
|
|
@ -9,8 +9,9 @@
|
|||
import { times } from 'lodash';
|
||||
import { elasticsearchSpan, httpExitSpan, HttpMethod, redisSpan, sqliteSpan } from '../apm/span';
|
||||
import { BaseSpan } from '../apm/base_span';
|
||||
import { Instance, SpanParams } from '../apm/instance';
|
||||
import { Instance } from '../apm/instance';
|
||||
import { Transaction } from '../apm/transaction';
|
||||
import { SpanParams } from '../apm/apm_fields';
|
||||
|
||||
export class DistributedTrace {
|
||||
timestamp: number;
|
||||
|
|
425
packages/kbn-apm-synthtrace/src/scenarios/mobile.ts
Normal file
425
packages/kbn-apm-synthtrace/src/scenarios/mobile.ts
Normal file
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* 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 { apm, timerange } from '../..';
|
||||
import {
|
||||
DeviceInfo,
|
||||
MobileDevice,
|
||||
OSInfo,
|
||||
GeoInfo,
|
||||
NetworkConnectionInfo,
|
||||
} from '../lib/apm/mobile_device';
|
||||
import { ApmFields } from '../lib/apm/apm_fields';
|
||||
import { Scenario } from '../cli/scenario';
|
||||
import { getLogger } from '../cli/utils/get_common_services';
|
||||
import { RunOptions } from '../cli/utils/parse_run_cli_flags';
|
||||
import { getSynthtraceEnvironment } from '../lib/utils/get_synthtrace_environment';
|
||||
|
||||
const ENVIRONMENT = getSynthtraceEnvironment(__filename);
|
||||
|
||||
type DeviceMetadata = DeviceInfo & OSInfo;
|
||||
|
||||
const ANDROID_DEVICES: DeviceMetadata[] = [
|
||||
{
|
||||
manufacturer: 'Samsung',
|
||||
modelIdentifier: 'SM-G930F',
|
||||
modelName: 'Galaxy S7',
|
||||
osType: 'android',
|
||||
osVersion: '10',
|
||||
osFull: 'Android 10, API level 29, BUILD A022MUBU2AUD1',
|
||||
runtimeVersion: '2.1.0',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Samsung',
|
||||
modelIdentifier: 'SM-G973F',
|
||||
modelName: 'Galaxy S10',
|
||||
osType: 'android',
|
||||
osVersion: '13',
|
||||
osFull: 'Android 13, API level 3, BUILD X0ETMUBU2AER2',
|
||||
runtimeVersion: '2.0.0',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Samsung',
|
||||
modelIdentifier: 'SM-N950F',
|
||||
modelName: 'Galaxy Note8',
|
||||
osType: 'android',
|
||||
osVersion: '10',
|
||||
osFull: 'Android 10, API level 29, BUILD A022MUBU2AUD1',
|
||||
runtimeVersion: '2.1.0',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Huawei',
|
||||
modelIdentifier: 'HUAWEI P2-0000',
|
||||
osType: 'android',
|
||||
osVersion: '10',
|
||||
osFull: 'Android 10, API level 29, BUILD A022MUBU2AUD1',
|
||||
runtimeVersion: '2.1.0',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Huawei',
|
||||
modelIdentifier: 'HUAWEI NXT-CL00',
|
||||
modelName: 'Mate8',
|
||||
osType: 'android',
|
||||
osVersion: '10',
|
||||
osFull: 'Android 10, API level 29, BUILD A022MUBU2AUD1',
|
||||
runtimeVersion: '2.1.0',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Huawei',
|
||||
modelIdentifier: 'T1-701u',
|
||||
modelName: 'MediaPad',
|
||||
osType: 'android',
|
||||
osVersion: '10',
|
||||
osFull: 'Android 13, API level 29, BUILD X0ETMUBU2AER2',
|
||||
runtimeVersion: '2.0.0',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Google',
|
||||
modelIdentifier: 'Pixel 3a',
|
||||
modelName: 'Pixel 3a',
|
||||
osType: 'android',
|
||||
osVersion: '10',
|
||||
osFull: 'Android 10, API level 29, BUILD A022MUBU2AUD1',
|
||||
runtimeVersion: '2.1.0',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Google',
|
||||
modelIdentifier: 'Pixel 7 Pro',
|
||||
modelName: 'Pixel 7 Pro',
|
||||
osType: 'android',
|
||||
osVersion: '10',
|
||||
osFull: 'Android 10, API level 29, BUILD A022MUBU2AUD1',
|
||||
runtimeVersion: '2.1.0',
|
||||
},
|
||||
{
|
||||
manufacturer: 'LGE',
|
||||
modelIdentifier: 'LG G6',
|
||||
modelName: 'LG-LS993',
|
||||
osType: 'android',
|
||||
osVersion: '10',
|
||||
osFull: 'Android 12, API level 31, BUILD KJSJADSlKSDAA',
|
||||
runtimeVersion: '1.9.0',
|
||||
},
|
||||
{
|
||||
manufacturer: 'LGE',
|
||||
modelIdentifier: 'LG K10',
|
||||
modelName: 'LG-K425',
|
||||
osType: 'android',
|
||||
osVersion: '10',
|
||||
osFull: 'Android 12, API level 32, BUILD KJSJA342SlKSD',
|
||||
runtimeVersion: '1.9.0',
|
||||
},
|
||||
];
|
||||
|
||||
const APPLE_DEVICES: DeviceMetadata[] = [
|
||||
{
|
||||
manufacturer: 'Apple',
|
||||
modelIdentifier: 'iPhone15,2',
|
||||
modelName: 'iPhone 14 Pro',
|
||||
osType: 'ios',
|
||||
osVersion: '16',
|
||||
osFull: 'iOS 16',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Apple',
|
||||
modelIdentifier: 'iPhone14,5',
|
||||
modelName: 'iPhone 13',
|
||||
osType: 'ios',
|
||||
osVersion: '15',
|
||||
osFull: 'iOS 15',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Apple',
|
||||
modelIdentifier: 'iPhone11,8',
|
||||
modelName: 'iPhone XR',
|
||||
osType: 'ios',
|
||||
osVersion: '11',
|
||||
osFull: 'iOS 11',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Apple',
|
||||
modelIdentifier: 'iPhone9,1',
|
||||
modelName: 'iPhone 7',
|
||||
osType: 'ios',
|
||||
osVersion: '9',
|
||||
osFull: 'iOS 9',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Apple',
|
||||
modelIdentifier: 'iPhone13,2',
|
||||
modelName: 'iPhone 12',
|
||||
osType: 'ios',
|
||||
osVersion: '13',
|
||||
osFull: 'iOS 13',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Apple',
|
||||
modelIdentifier: 'iPad12,2',
|
||||
modelName: 'iPad 9th Gen',
|
||||
osType: 'ios',
|
||||
osVersion: '12',
|
||||
osFull: 'iOS 12',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Apple',
|
||||
modelIdentifier: 'iPad13,7',
|
||||
modelName: 'iPad Pro 11 inch 5th Gen',
|
||||
osType: 'ios',
|
||||
osVersion: '13',
|
||||
osFull: 'iPadOS 13',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Apple',
|
||||
modelIdentifier: 'iPad13,11',
|
||||
modelName: 'iPad Pro 12.9 inch 5th Gen',
|
||||
osType: 'ios',
|
||||
osVersion: '13',
|
||||
osFull: 'iPadOS 13',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Apple',
|
||||
modelIdentifier: 'iPad13,19',
|
||||
modelName: 'iPad 10th Gen',
|
||||
osType: 'ios',
|
||||
osVersion: '13',
|
||||
osFull: 'iPadOS 13',
|
||||
},
|
||||
{
|
||||
manufacturer: 'Apple',
|
||||
modelIdentifier: 'Watch6,8',
|
||||
modelName: 'Apple Watch Series 7 41mm case',
|
||||
osType: 'ios',
|
||||
osVersion: '6',
|
||||
osFull: 'WatchOS 6',
|
||||
},
|
||||
];
|
||||
|
||||
type GeoAndNetwork = GeoInfo & NetworkConnectionInfo;
|
||||
|
||||
const GEO_AND_NETWORK: GeoAndNetwork[] = [
|
||||
{
|
||||
clientIp: '223.72.43.22',
|
||||
cityName: 'Beijing',
|
||||
continentName: 'Asia',
|
||||
countryIsoCode: 'CN',
|
||||
countryName: 'China',
|
||||
regionIsoCode: 'CN-BJ',
|
||||
regionName: 'Beijing',
|
||||
location: { coordinates: [116.3861, 39.9143], type: 'Point' },
|
||||
type: 'wifi',
|
||||
},
|
||||
{
|
||||
clientIp: '20.24.184.101',
|
||||
cityName: 'Singapore',
|
||||
continentName: 'Asia',
|
||||
countryIsoCode: 'SG',
|
||||
countryName: 'Singapore',
|
||||
location: { coordinates: [103.8554, 1.3036], type: 'Point' },
|
||||
type: 'cell',
|
||||
subType: 'edge',
|
||||
carrierName: 'M1 Limited',
|
||||
carrierMNC: '03',
|
||||
carrierICC: 'SG',
|
||||
carrierMCC: '525',
|
||||
},
|
||||
{
|
||||
clientIp: '178.173.228.103',
|
||||
cityName: 'Tokyo',
|
||||
continentName: 'Asia',
|
||||
countryIsoCode: 'JP',
|
||||
countryName: 'Japan',
|
||||
regionIsoCode: 'JP-13',
|
||||
regionName: 'Tokyo',
|
||||
location: { coordinates: [139.7425, 35.6164], type: 'Point' },
|
||||
type: 'cell',
|
||||
subType: 'edge',
|
||||
carrierName: 'Osaka Gas Business Create Co., Ltd.',
|
||||
carrierMNC: '17',
|
||||
carrierICC: 'JP',
|
||||
carrierMCC: '440',
|
||||
},
|
||||
{
|
||||
clientIp: '147.161.184.179',
|
||||
cityName: 'Paris',
|
||||
continentName: 'Europe',
|
||||
countryIsoCode: 'FR',
|
||||
countryName: 'France',
|
||||
regionIsoCode: 'FR-75',
|
||||
regionName: 'Paris',
|
||||
location: { coordinates: [2.4075, 48.8323], type: 'Point' },
|
||||
type: 'cell',
|
||||
subType: 'hspa',
|
||||
carrierName: 'Altice',
|
||||
carrierMNC: '09',
|
||||
carrierICC: 'FR',
|
||||
carrierMCC: '208',
|
||||
},
|
||||
{
|
||||
clientIp: '34.136.92.88',
|
||||
cityName: 'Council Bluffs',
|
||||
continentName: 'North America',
|
||||
countryIsoCode: 'US',
|
||||
countryName: 'United States',
|
||||
regionIsoCode: 'US-IA',
|
||||
regionName: 'Iowa',
|
||||
location: { coordinates: [-95.8517, 41.2591], type: 'Point' },
|
||||
type: 'cell',
|
||||
subType: 'lte',
|
||||
carrierName: 'Midwest Network Solutions Hub LLC',
|
||||
carrierMNC: '070',
|
||||
carrierICC: 'US',
|
||||
carrierMCC: '313',
|
||||
},
|
||||
{
|
||||
clientIp: '163.116.135.123',
|
||||
cityName: 'New York',
|
||||
continentName: 'North America',
|
||||
countryIsoCode: 'US',
|
||||
countryName: 'United States',
|
||||
regionIsoCode: 'US-NY',
|
||||
regionName: 'New York',
|
||||
location: { coordinates: [-73.9877, 40.7425], type: 'Point' },
|
||||
type: 'cell',
|
||||
subType: 'lte',
|
||||
carrierName: 'Texas A&M University',
|
||||
carrierMNC: '080',
|
||||
carrierICC: 'US',
|
||||
carrierMCC: '314',
|
||||
},
|
||||
{
|
||||
clientIp: '163.116.178.27',
|
||||
cityName: 'Frankfurt am Main',
|
||||
continentName: 'Europe',
|
||||
countryIsoCode: 'DE',
|
||||
countryName: 'Germany',
|
||||
regionIsoCode: 'DE-HE',
|
||||
regionName: 'Hesse',
|
||||
location: { coordinates: [8.6843, 50.1188], type: 'Point' },
|
||||
type: 'cell',
|
||||
subType: 'lte',
|
||||
carrierName: 'Telekom Deutschland GmbH',
|
||||
carrierMNC: '06',
|
||||
carrierICC: 'DE',
|
||||
carrierMCC: '262',
|
||||
},
|
||||
];
|
||||
|
||||
function randomInt(max: number) {
|
||||
return Math.floor(Math.random() * max);
|
||||
}
|
||||
|
||||
const scenario: Scenario<ApmFields> = async (runOptions: RunOptions) => {
|
||||
const logger = getLogger(runOptions);
|
||||
|
||||
const { numDevices = 10 } = runOptions.scenarioOpts || {};
|
||||
|
||||
return {
|
||||
generate: ({ from, to }) => {
|
||||
const range = timerange(from, to);
|
||||
|
||||
const androidDevices = [...Array(numDevices).keys()].map((index) => {
|
||||
const deviceMetadata = ANDROID_DEVICES[randomInt(ANDROID_DEVICES.length)];
|
||||
const geoNetwork = GEO_AND_NETWORK[randomInt(GEO_AND_NETWORK.length)];
|
||||
return apm
|
||||
.mobileApp({ name: 'synth-android', environment: ENVIRONMENT, agentName: 'android/java' })
|
||||
.mobileDevice()
|
||||
.deviceInfo(deviceMetadata)
|
||||
.osInfo(deviceMetadata)
|
||||
.setGeoInfo(geoNetwork)
|
||||
.setNetworkConnection(geoNetwork);
|
||||
});
|
||||
|
||||
const iOSDevices = [...Array(numDevices).keys()].map((index) => {
|
||||
const deviceMetadata = APPLE_DEVICES[randomInt(APPLE_DEVICES.length)];
|
||||
const geoNetwork = GEO_AND_NETWORK[randomInt(GEO_AND_NETWORK.length)];
|
||||
return apm
|
||||
.mobileApp({ name: 'synth-ios', environment: ENVIRONMENT, agentName: 'iOS/swift' })
|
||||
.mobileDevice()
|
||||
.deviceInfo(deviceMetadata)
|
||||
.osInfo(deviceMetadata)
|
||||
.setGeoInfo(geoNetwork)
|
||||
.setNetworkConnection(geoNetwork);
|
||||
});
|
||||
|
||||
const clickRate = range.ratePerMinute(2);
|
||||
|
||||
const sessionTransactions = (device: MobileDevice) => {
|
||||
return clickRate.generator((timestamp, index) => {
|
||||
device.startNewSession();
|
||||
const framework =
|
||||
device.fields['device.manufacturer'] === 'Apple' ? 'iOS' : 'Android Activity';
|
||||
return [
|
||||
device
|
||||
.transaction('Start View - View Appearing', framework)
|
||||
.timestamp(timestamp)
|
||||
.duration(500)
|
||||
.success()
|
||||
.children(
|
||||
device
|
||||
.span({
|
||||
spanName: 'onCreate',
|
||||
spanType: 'app',
|
||||
spanSubtype: 'internal',
|
||||
})
|
||||
.duration(50)
|
||||
.success()
|
||||
.timestamp(timestamp + 20),
|
||||
device
|
||||
.httpSpan({
|
||||
spanName: 'GET backend:1234',
|
||||
httpMethod: 'GET',
|
||||
httpUrl: 'https://backend:1234/api/start',
|
||||
})
|
||||
.duration(800)
|
||||
.success()
|
||||
.timestamp(timestamp + 400)
|
||||
),
|
||||
device
|
||||
.transaction('Second View - View Appearing', framework)
|
||||
.timestamp(10000 + timestamp)
|
||||
.duration(300)
|
||||
.success()
|
||||
.children(
|
||||
device
|
||||
.httpSpan({
|
||||
spanName: 'GET backend:1234',
|
||||
httpMethod: 'GET',
|
||||
httpUrl: 'https://backend:1234/api/second',
|
||||
})
|
||||
.duration(400)
|
||||
.success()
|
||||
.timestamp(10000 + timestamp + 250)
|
||||
),
|
||||
device
|
||||
.transaction('Third View - View Appearing', framework)
|
||||
.timestamp(20000 + timestamp)
|
||||
.duration(300)
|
||||
.success()
|
||||
.children(
|
||||
device
|
||||
.span({
|
||||
spanName: 'onCreate',
|
||||
spanType: 'app',
|
||||
spanSubtype: 'internal',
|
||||
})
|
||||
.duration(50)
|
||||
.success()
|
||||
.timestamp(20000 + timestamp + 20)
|
||||
),
|
||||
];
|
||||
});
|
||||
};
|
||||
|
||||
return [...androidDevices, ...iOSDevices]
|
||||
.map((device) => logger.perf('generating_apm_events', () => sessionTransactions(device)))
|
||||
.reduce((p, c) => p.merge(c));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default scenario;
|
Loading…
Add table
Add a link
Reference in a new issue