diff --git a/.i18nrc.json b/.i18nrc.json index 034b9da799d3e..9af7f17067b8e 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -56,7 +56,8 @@ "visTypeVislib": "src/plugins/vis_type_vislib", "visTypeXy": "src/plugins/vis_type_xy", "visualizations": "src/plugins/visualizations", - "visualize": "src/plugins/visualize" + "visualize": "src/plugins/visualize", + "apmOss": "src/plugins/apm_oss" }, "exclude": [ "src/legacy/ui/ui_render/ui_render_mixin.js" diff --git a/docs/apm/api.asciidoc b/docs/apm/api.asciidoc index b26c7446b91d1..3e4b515e009de 100644 --- a/docs/apm/api.asciidoc +++ b/docs/apm/api.asciidoc @@ -9,14 +9,45 @@ Some APM app features are provided via a REST API: * <> - -TIP: Kibana provides additional <>, -and general information on <>. +* <> + +Here's an example CURL request that adds an annotation to the APM app: + +[source,curl] +---- +curl -X POST \ + http://localhost:5601/api/apm/services/opbeans-java/annotation \ +-H 'Content-Type: application/json' \ +-H 'kbn-xsrf: true' \ +-H 'Authorization: Basic YhUlubWZhM0FDbnlQeE6WRtaW49FQmSGZ4RUWXdX' \ +-d '{ + "@timestamp": "2020-05-11T10:31:30.452Z", + "service": { + "version": "1.2" + }, + "message": "Revert upgrade", + "tags": [ + "elastic.co", "customer" + ] + }' +---- + +For more information, the Kibana <> provides information on how to use Kibana APIs, +like required request headers and authentication options. + +// AGENT CONFIG API +// GET --> Feature (APM) Read +// CREATE/EDIT/DELETE --> Feature (APM) All + +// ANNOTATION API +// Feature (APM) All +// Index: `observability-annotations`. Privileges: `create_index`, `create_doc`, `manage`, and `read`. //// ******************************************************* //// +[role="xpack"] [[agent-config-api]] === Agent Configuration API @@ -274,6 +305,118 @@ POST /api/apm/settings/agent-configuration/search } -------------------------------------------------- +//// +******************************************************* +******************************************************* +//// + +[role="xpack"] +[[apm-annotation-api]] +=== Annotation API + +The Annotation API allows you to annotate visualizations in the APM app with significant events, like deployments, +allowing you to easily see how these events are impacting the performance of your existing applications. + +The following APIs are available: + +* <> to create an annotation for APM. +// * <> POST /api/observability/annotation +// * <> GET /api/observability/annotation/:id +// * <> DELETE /api/observability/annotation/:id + +By default, annotations are stored in a newly created `observability-annotations` index. +The name of this index can be changed in your `config.yml` by editing `xpack.observability.annotations.index`. + //// ******************************************************* //// + +[[apm-annotation-create]] +==== Create or update annotation + +[[apm-annotation-config-req]] +===== Request + +`POST /api/apm/services/:serviceName/annotation` + +[role="child_attributes"] +[[apm-annotation-config-req-body]] +===== Request body + +`service`:: +(required, object) Service identifying the configuration to create or update. ++ +.Properties of `service` +[%collapsible%open] +====== +`version` ::: + (required, string) Name of service. + +`environment` ::: + (optional, string) Environment of service. +====== + +`@timestamp`:: +(required, string) The date and time of the annotation. Must be in https://www.w3.org/TR/NOTE-datetime[ISO 8601] format. + +`message`:: +(optional, string) The message displayed in the annotation. Defaults to `service.version`. + +`tags`:: +(optional, array) Tags are used by the APM app to distinguish APM annotations from other annotations. +Tags may have additional functionality in future releases. Defaults to `[apm]`. +While you can add additional tags, you cannot remove the `apm` tag. + +[[apm-annotation-config-example]] +===== Example + +The following example creates an annotation for a service named `opbeans-java`. + +[source,console] +-------------------------------------------------- +POST /api/apm/services/opbeans-java/annotation +{ + "@timestamp": "2020-05-08T10:31:30.452Z", + "service": { + "version": "1.2" + }, + "message": "Deployment 1.2", + "tags": [ + "elastic.co", "customer" + ] +} +-------------------------------------------------- + +[[apm-annotation-config-body]] +===== Response body + +[source,js] +-------------------------------------------------- +{ + "_index": "observability-annotations", + "_id": "Lc9I93EBh6DbmkeV7nFX", + "_version": 1, + "_seq_no": 12, + "_primary_term": 1, + "found": true, + "_source": { + "message": "Deployment 1.2", + "@timestamp": "2020-05-08T10:31:30.452Z", + "service": { + "version": "1.2", + "name": "opbeans-java" + }, + "tags": [ + "apm", + "elastic.co", + "customer" + ], + "annotation": { + "type": "deployment" + }, + "event": { + "created": "2020-05-09T02:34:43.937Z" + } + } +} +-------------------------------------------------- diff --git a/docs/apm/deployment-annotations.asciidoc b/docs/apm/deployment-annotations.asciidoc index 6feadf8463226..9abcd9f6efc74 100644 --- a/docs/apm/deployment-annotations.asciidoc +++ b/docs/apm/deployment-annotations.asciidoc @@ -3,7 +3,7 @@ === Track deployments with annotations ++++ -Track deployments +Track deployments with annotations ++++ For enhanced visibility into your deployments, we offer deployment annotations on all transaction charts. @@ -11,7 +11,11 @@ This feature automatically tags new deployments, so you can easily see if your d for an end-user, or if the memory/CPU footprint of your application has changed. Being able to identify bad deployments quickly enables you to rollback and fix issues without causing costly outages. -Deployment annotations are automatically enabled, and appear when the `service.version` of your app changes. +Deployment annotations are enabled by default, and can be created with the <>. +If there are no created annotations for the selected time period, +the APM app will automatically annotate your data if the `service.version` of your application changes. + +NOTE: If custom annotations have been created for the selected time period, any derived annotations, i.e., those created automatically when `service.version` changes, will not be shown. [role="screenshot"] image::apm/images/apm-transaction-annotation.png[Example view of transactions annotation in the APM app in Kibana] diff --git a/docs/apm/images/apm-transaction-annotation.png b/docs/apm/images/apm-transaction-annotation.png index bc71b1d2169c4..8913770517ff6 100644 Binary files a/docs/apm/images/apm-transaction-annotation.png and b/docs/apm/images/apm-transaction-annotation.png differ diff --git a/docs/settings/apm-settings.asciidoc b/docs/settings/apm-settings.asciidoc index efc43e5d2f52d..b781930485243 100644 --- a/docs/settings/apm-settings.asciidoc +++ b/docs/settings/apm-settings.asciidoc @@ -52,6 +52,9 @@ Changing these settings may disable features of the APM App. | `xpack.apm.ui.maxTraceItems` {ess-icon} | Maximum number of child items displayed when viewing trace details. Defaults to `1000`. +| `xpack.observability.annotations.index` + | Index name where Observability annotations are stored. Defaults to `observability-annotations`. + | `apm_oss.indexPattern` {ess-icon} | The index pattern used for integrations with Machine Learning and Query Bar. It must match all apm indices. Defaults to `apm-*`. diff --git a/package.json b/package.json index 72a63ec34d2c7..634720d6d3a2f 100644 --- a/package.json +++ b/package.json @@ -240,7 +240,7 @@ "react-dom": "^16.12.0", "react-grid-layout": "^0.16.2", "react-input-range": "^1.3.0", - "react-markdown": "^3.4.1", + "react-markdown": "^4.3.1", "react-monaco-editor": "~0.27.0", "react-redux": "^7.1.3", "react-resize-detector": "^4.2.0", @@ -298,7 +298,6 @@ "@elastic/eslint-plugin-eui": "0.0.2", "@elastic/github-checks-reporter": "0.0.20b3", "@elastic/makelogs": "^5.0.1", - "@elastic/static-fs": "1.0.2", "@kbn/dev-utils": "1.0.0", "@kbn/es": "1.0.0", "@kbn/eslint-import-resolver-kibana": "2.0.0", @@ -387,7 +386,7 @@ "@types/semver": "^5.5.0", "@types/sinon": "^7.0.13", "@types/strip-ansi": "^3.0.0", - "@types/styled-components": "^4.4.2", + "@types/styled-components": "^5.1.0", "@types/supertest": "^2.0.5", "@types/supertest-as-promised": "^2.0.38", "@types/testing-library__react": "^9.1.2", diff --git a/packages/kbn-babel-preset/package.json b/packages/kbn-babel-preset/package.json index 1a2f6941c2020..ba0c2489cdbc1 100644 --- a/packages/kbn-babel-preset/package.json +++ b/packages/kbn-babel-preset/package.json @@ -14,7 +14,7 @@ "@babel/preset-typescript": "^7.9.0", "babel-plugin-add-module-exports": "^1.0.2", "babel-plugin-filter-imports": "^3.0.0", - "babel-plugin-styled-components": "^1.10.6", + "babel-plugin-styled-components": "^1.10.7", "babel-plugin-transform-define": "^1.3.1", "babel-plugin-transform-imports": "^2.0.0" } diff --git a/packages/kbn-optimizer/src/common/index.ts b/packages/kbn-optimizer/src/common/index.ts index c51905be04565..376b9ed350908 100644 --- a/packages/kbn-optimizer/src/common/index.ts +++ b/packages/kbn-optimizer/src/common/index.ts @@ -21,6 +21,7 @@ export * from './bundle'; export * from './bundle_cache'; export * from './worker_config'; export * from './worker_messages'; +export * from './parent_messages'; export * from './compiler_messages'; export * from './ts_helpers'; export * from './rxjs_helpers'; diff --git a/packages/kbn-optimizer/src/common/parent_messages.ts b/packages/kbn-optimizer/src/common/parent_messages.ts new file mode 100644 index 0000000000000..c27bcb96f4a89 --- /dev/null +++ b/packages/kbn-optimizer/src/common/parent_messages.ts @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export interface ParentPongMsg { + type: 'pong'; +} + +export const isParentPong = (value: any): value is ParentPongMsg => + typeof value === 'object' && value && value.type === 'pong'; + +export class ParentMsgs { + pong(): ParentPongMsg { + return { + type: 'pong', + }; + } +} diff --git a/packages/kbn-optimizer/src/common/worker_messages.ts b/packages/kbn-optimizer/src/common/worker_messages.ts index d3c03f483d7e8..0435f5b4c4011 100644 --- a/packages/kbn-optimizer/src/common/worker_messages.ts +++ b/packages/kbn-optimizer/src/common/worker_messages.ts @@ -24,13 +24,17 @@ import { CompilerErrorMsg, } from './compiler_messages'; -export type WorkerMsg = +export type InternalWorkerMsg = + | WorkerPingMsg | CompilerRunningMsg | CompilerIssueMsg | CompilerSuccessMsg | CompilerErrorMsg | WorkerErrorMsg; +// ping messages are internal, they don't apper in public message streams +export type WorkerMsg = Exclude; + /** * Message sent when the worker encounters an error that it can't * recover from, no more messages will be sent and the worker @@ -42,6 +46,10 @@ export interface WorkerErrorMsg { errorStack?: string; } +export interface WorkerPingMsg { + type: 'ping'; +} + const WORKER_STATE_TYPES: ReadonlyArray = [ 'running', 'compiler issue', @@ -50,10 +58,19 @@ const WORKER_STATE_TYPES: ReadonlyArray = [ 'worker error', ]; +export const isWorkerPing = (value: any): value is WorkerPingMsg => + typeof value === 'object' && value && value.type === 'ping'; + export const isWorkerMsg = (value: any): value is WorkerMsg => typeof value === 'object' && value && WORKER_STATE_TYPES.includes(value.type); export class WorkerMsgs { + ping(): WorkerPingMsg { + return { + type: 'ping', + }; + } + error(error: Error): WorkerErrorMsg { return { type: 'worker error', diff --git a/packages/kbn-optimizer/src/optimizer/observe_worker.ts b/packages/kbn-optimizer/src/optimizer/observe_worker.ts index bfc853e5a6b75..90c53f1ef9e87 100644 --- a/packages/kbn-optimizer/src/optimizer/observe_worker.ts +++ b/packages/kbn-optimizer/src/optimizer/observe_worker.ts @@ -22,12 +22,14 @@ import { Readable } from 'stream'; import { inspect } from 'util'; import * as Rx from 'rxjs'; -import { map, takeUntil } from 'rxjs/operators'; +import { map, filter, takeUntil } from 'rxjs/operators'; -import { isWorkerMsg, WorkerConfig, WorkerMsg, Bundle } from '../common'; +import { isWorkerMsg, isWorkerPing, WorkerConfig, WorkerMsg, Bundle, ParentMsgs } from '../common'; import { OptimizerConfig } from './optimizer_config'; +const parentMsgs = new ParentMsgs(); + export interface WorkerStdio { type: 'worker stdio'; stream: 'stdout' | 'stderr'; @@ -146,6 +148,16 @@ export function observeWorker( observeStdio$(proc.stderr, 'stderr'), Rx.fromEvent<[unknown]>(proc, 'message') .pipe( + // filter out ping messages so they don't end up in the general message stream + filter(([msg]) => { + if (!isWorkerPing(msg)) { + return true; + } + + proc.send(parentMsgs.pong()); + return false; + }), + // validate the messages from the process map(([msg]) => { if (!isWorkerMsg(msg)) { diff --git a/packages/kbn-optimizer/src/worker/observe_parent_offline.test.ts b/packages/kbn-optimizer/src/worker/observe_parent_offline.test.ts new file mode 100644 index 0000000000000..353f570e2cacc --- /dev/null +++ b/packages/kbn-optimizer/src/worker/observe_parent_offline.test.ts @@ -0,0 +1,178 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { EventEmitter } from 'events'; +import { inspect } from 'util'; + +import * as Rx from 'rxjs'; +import { tap, takeUntil } from 'rxjs/operators'; + +import { observeParentOffline, Process } from './observe_parent_offline'; +import { WorkerMsgs, ParentMsgs, isWorkerPing } from '../common'; + +jest.useFakeTimers(); + +beforeEach(() => { + jest.clearAllTimers(); +}); + +const workerMsgs = new WorkerMsgs(); +const parentMsgs = new ParentMsgs(); +class MockProcess extends EventEmitter implements Process { + connected?: boolean; + send?: jest.Mock; + + constructor(options: { connected?: boolean; send?: jest.Mock | false } = {}) { + super(); + + this.connected = options.connected ?? true; + this.send = options.send === false ? undefined : options.send ?? jest.fn(); + } +} + +async function record(observable: Rx.Observable): Promise { + const notes: string[] = []; + + await observable + .pipe( + tap({ + next(value) { + notes.push(`next: ${inspect(value)}`); + }, + error(error) { + notes.push(`error: ${inspect(error)}`); + }, + complete() { + notes.push(`complete`); + }, + }) + ) + .toPromise(); + + return notes; +} + +async function waitForTick() { + await new Promise(resolve => { + process.nextTick(resolve); + }); +} + +describe('emits and completes when parent exists because:', () => { + test('"disconnect" event', async () => { + const mockProc = new MockProcess(); + const promise = record(observeParentOffline(mockProc, workerMsgs)); + mockProc.emit('disconnect'); + expect(await promise).toMatchInlineSnapshot(` + Array [ + "next: 'parent offline (disconnect event)'", + "complete", + ] + `); + }); + + test('process.connected is false', async () => { + const mockProc = new MockProcess({ + connected: false, + }); + + const promise = record(observeParentOffline(mockProc, workerMsgs)); + jest.advanceTimersToNextTimer(); + expect(await promise).toMatchInlineSnapshot(` + Array [ + "next: 'parent offline (disconnected)'", + "complete", + ] + `); + }); + + test('process.send is falsey', async () => { + const mockProc = new MockProcess({ + send: false, + }); + + const promise = record(observeParentOffline(mockProc, workerMsgs)); + jest.advanceTimersToNextTimer(); + expect(await promise).toMatchInlineSnapshot(` + Array [ + "next: 'parent offline (disconnected)'", + "complete", + ] + `); + }); + + test('process.send throws "ERR_IPC_CHANNEL_CLOSED"', async () => { + const mockProc = new MockProcess({ + send: jest.fn(() => { + const error = new Error(); + (error as any).code = 'ERR_IPC_CHANNEL_CLOSED'; + throw error; + }), + }); + + const promise = record(observeParentOffline(mockProc, workerMsgs)); + jest.advanceTimersToNextTimer(); + expect(await promise).toMatchInlineSnapshot(` + Array [ + "next: 'parent offline (ipc channel exception)'", + "complete", + ] + `); + }); + + test('ping timeout', async () => { + const mockProc = new MockProcess({}); + + const promise = record(observeParentOffline(mockProc, workerMsgs)); + jest.advanceTimersByTime(10000); + expect(await promise).toMatchInlineSnapshot(` + Array [ + "next: 'parent offline (ping timeout)'", + "complete", + ] + `); + }); +}); + +test('it emits nothing if parent responds with pongs', async () => { + const send = jest.fn((msg: any) => { + if (isWorkerPing(msg)) { + process.nextTick(() => { + mockProc.emit('message', parentMsgs.pong(), undefined); + }); + } + }); + + const mockProc = new MockProcess({ send }); + const unsub$ = new Rx.Subject(); + const promise = record(observeParentOffline(mockProc, workerMsgs).pipe(takeUntil(unsub$))); + + jest.advanceTimersByTime(5000); + await waitForTick(); + jest.advanceTimersByTime(5000); + await waitForTick(); + unsub$.next(); + + expect(await promise).toMatchInlineSnapshot(` + Array [ + "complete", + ] + `); + expect(send).toHaveBeenCalledTimes(2); +}); diff --git a/packages/kbn-optimizer/src/worker/observe_parent_offline.ts b/packages/kbn-optimizer/src/worker/observe_parent_offline.ts new file mode 100644 index 0000000000000..94ec34b409dd4 --- /dev/null +++ b/packages/kbn-optimizer/src/worker/observe_parent_offline.ts @@ -0,0 +1,97 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { EventEmitter } from 'events'; + +import * as Rx from 'rxjs'; +import { mergeMap, take, first, map, catchError } from 'rxjs/operators'; + +import { isParentPong, WorkerMsgs } from '../common'; + +const sleep = (ms: number) => Rx.timer(ms).pipe(take(1)); + +export interface Process extends EventEmitter { + connected?: boolean; + send?: (msg: any) => void; +} + +/** + * Returns an observable that will emit a value when the parent + * process goes offline. It accomplishes this by merging several + * signals: + * + * 1. process "disconnect" event + * 2. process.connected or process.send are falsy + * 3. a ping was sent to the parent process but it didn't respond + * with a pong within 5 seconds + * 4. a ping was sent to the parent process but the process.send + * call errored with an 'ERR_IPC_CHANNEL_CLOSED' exception + */ +export function observeParentOffline(process: Process, workerMsgs: WorkerMsgs) { + return Rx.race( + Rx.fromEvent(process, 'disconnect').pipe( + take(1), + map(() => 'parent offline (disconnect event)') + ), + + sleep(5000).pipe( + mergeMap(() => { + if (!process.connected || !process.send) { + return Rx.of('parent offline (disconnected)'); + } + + process.send(workerMsgs.ping()); + + const pong$ = Rx.fromEvent<[any]>(process, 'message').pipe( + first(([msg]) => isParentPong(msg)), + map(() => { + throw new Error('parent still online'); + }) + ); + + // give the parent some time to respond, if the ping + // wins the race the parent is considered online + const timeout$ = sleep(5000).pipe(map(() => 'parent offline (ping timeout)')); + + return Rx.race(pong$, timeout$); + }) + ) + ).pipe( + /** + * resubscribe to the source observable (triggering the timer, + * ping, wait for response) if the source observable does not + * observe the parent being offline yet. + * + * Scheduling the interval this way prevents the ping timeout + * from overlaping with the interval by only scheduling the + * next ping once the previous ping has completed + */ + catchError((error, resubscribe) => { + if (error.code === 'ERR_IPC_CHANNEL_CLOSED') { + return Rx.of('parent offline (ipc channel exception)'); + } + + if (error.message === 'parent still online') { + return resubscribe; + } + + throw error; + }) + ); +} diff --git a/packages/kbn-optimizer/src/worker/run_worker.ts b/packages/kbn-optimizer/src/worker/run_worker.ts index cbec4c3f44c7d..0a9adc2a3db55 100644 --- a/packages/kbn-optimizer/src/worker/run_worker.ts +++ b/packages/kbn-optimizer/src/worker/run_worker.ts @@ -18,10 +18,12 @@ */ import * as Rx from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import { parseBundles, parseWorkerConfig, WorkerMsg, isWorkerMsg, WorkerMsgs } from '../common'; import { runCompilers } from './run_compilers'; +import { observeParentOffline } from './observe_parent_offline'; /** ** @@ -64,15 +66,6 @@ const exit = (code: number) => { }, 5000).unref(); }; -// check for connected parent on an unref'd timer rather than listening -// to "disconnect" since that listner prevents the process from exiting -setInterval(() => { - if (!process.connected) { - // parent is gone - process.exit(0); - } -}, 1000).unref(); - Rx.defer(() => { const workerConfig = parseWorkerConfig(process.argv[2]); const bundles = parseBundles(process.argv[3]); @@ -81,20 +74,22 @@ Rx.defer(() => { process.env.BROWSERSLIST_ENV = workerConfig.browserslistEnv; return runCompilers(workerConfig, bundles); -}).subscribe( - msg => { - send(msg); - }, - error => { - if (isWorkerMsg(error)) { - send(error); - } else { - send(workerMsgs.error(error)); - } +}) + .pipe(takeUntil(observeParentOffline(process, workerMsgs))) + .subscribe( + msg => { + send(msg); + }, + error => { + if (isWorkerMsg(error)) { + send(error); + } else { + send(workerMsgs.error(error)); + } - exit(1); - }, - () => { - exit(0); - } -); + exit(1); + }, + () => { + exit(0); + } + ); diff --git a/packages/kbn-storybook/package.json b/packages/kbn-storybook/package.json index 0b38554f7806c..f865a9fb47496 100644 --- a/packages/kbn-storybook/package.json +++ b/packages/kbn-storybook/package.json @@ -18,14 +18,14 @@ "fast-glob": "2.2.7", "glob-watcher": "5.0.3", "jest-specific-snapshot": "2.0.0", - "jest-styled-components": "6.3.1", + "jest-styled-components": "^7.0.2", "mkdirp": "0.5.1", "mini-css-extract-plugin": "0.7.0", "normalize-path": "3.0.0", "react-docgen-typescript-loader": "3.1.0", "rxjs": "6.5.2", "serve-static": "1.14.1", - "styled-components": "^3", + "styled-components": "^5.1.0", "webpack": "^4.41.5" } } \ No newline at end of file diff --git a/scripts/kibana.js b/scripts/kibana.js index 4da739469ffb1..f5a63e6c07dd6 100644 --- a/scripts/kibana.js +++ b/scripts/kibana.js @@ -17,6 +17,6 @@ * under the License. */ -require('../src/setup_node_env'); require('../src/apm')(process.env.ELASTIC_APM_PROXY_SERVICE_NAME || 'kibana-proxy'); +require('../src/setup_node_env'); require('../src/cli/cli'); diff --git a/src/cli/index.js b/src/cli/index.js index 6dbdd800268a9..45f88eaf82a5b 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -17,6 +17,6 @@ * under the License. */ -require('../setup_node_env'); require('../apm')(); +require('../setup_node_env'); require('./cli'); diff --git a/src/core/CONVENTIONS.md b/src/core/CONVENTIONS.md index c124169580337..447c6f396945f 100644 --- a/src/core/CONVENTIONS.md +++ b/src/core/CONVENTIONS.md @@ -68,7 +68,7 @@ my_plugin/    ├── index.ts    └── plugin.ts ``` -- [Manifest file](/docs/development/core/server/kibana-plugin-server.pluginmanifest.md) should be defined on top level. +- [Manifest file](/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md) should be defined on top level. - Both `server` and `public` should have an `index.ts` and a `plugin.ts` file: - `index.ts` should only contain: - The `plugin` export diff --git a/src/core/MIGRATION_EXAMPLES.md b/src/core/MIGRATION_EXAMPLES.md index c91c00bc1aa02..5cec20fb900f2 100644 --- a/src/core/MIGRATION_EXAMPLES.md +++ b/src/core/MIGRATION_EXAMPLES.md @@ -6,6 +6,7 @@ APIs to their New Platform equivalents. - [Migration Examples](#migration-examples) - [Configuration](#configuration) - [Declaring config schema](#declaring-config-schema) + - [Using New Platform config in a new plugin](#using-new-platform-config-in-a-new-plugin) - [Using New Platform config from a Legacy plugin](#using-new-platform-config-from-a-legacy-plugin) - [Create a New Platform plugin](#create-a-new-platform-plugin) - [HTTP Routes](#http-routes) @@ -15,11 +16,16 @@ APIs to their New Platform equivalents. - [4. New Platform plugin](#4-new-platform-plugin) - [Accessing Services](#accessing-services) - [Migrating Hapi "pre" handlers](#migrating-hapi-pre-handlers) + - [Simple example](#simple-example) + - [Full Example](#full-example) - [Chrome](#chrome) - - [Updating an application navlink](#updating-application-navlink) + - [Updating an application navlink](#updating-an-application-navlink) - [Chromeless Applications](#chromeless-applications) - [Render HTML Content](#render-html-content) - [Saved Objects types](#saved-objects-types) + - [Concrete example](#concrete-example) + - [Changes in structure compared to legacy](#changes-in-structure-compared-to-legacy) + - [Remarks](#remarks) - [UiSettings](#uisettings) ## Configuration @@ -65,7 +71,7 @@ export type MyPluginConfig = TypeOf; ### Using New Platform config in a new plugin After setting the config schema for your plugin, you might want to reach the configuration in the plugin. -It is provided as part of the [PluginInitializerContext](../../docs/development/core/server/kibana-plugin-server.plugininitializercontext.md) +It is provided as part of the [PluginInitializerContext](../../docs/development/core/server/kibana-plugin-core-server.plugininitializercontext.md) in the *constructor* of the plugin: ```ts @@ -210,9 +216,9 @@ new kibana.Plugin({ In the legacy platform, plugins have direct access to the Hapi `server` object which gives full access to all of Hapi's API. In the New Platform, plugins have access to the -[HttpServiceSetup](/docs/development/core/server/kibana-plugin-server.httpservicesetup.md) +[HttpServiceSetup](/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.md) interface, which is exposed via the -[CoreSetup](/docs/development/core/server/kibana-plugin-server.coresetup.md) +[CoreSetup](/docs/development/core/server/kibana-plugin-core-server.coresetup.md) object injected into the `setup` method of server-side plugins. This interface has a different API with slightly different behaviors. @@ -415,7 +421,7 @@ Services in the Legacy Platform were typically available via methods on either `server.plugins.*`, `server.*`, or `req.*`. In the New Platform, all services are available via the `context` argument to the route handler. The type of this argument is the -[RequestHandlerContext](/docs/development/core/server/kibana-plugin-server.requesthandlercontext.md). +[RequestHandlerContext](/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.md). The APIs available here will include all Core services and any services registered by plugins this plugin depends on. diff --git a/src/dev/build/build_distributables.js b/src/dev/build/build_distributables.js index 910313ac87059..6c2efeebc60c3 100644 --- a/src/dev/build/build_distributables.js +++ b/src/dev/build/build_distributables.js @@ -40,7 +40,6 @@ import { CreatePackageJsonTask, CreateReadmeTask, CreateRpmPackageTask, - CreateStaticFsWithNodeModulesTask, DownloadNodeBuildsTask, ExtractNodeBuildsTask, InstallDependenciesTask, @@ -127,7 +126,6 @@ export async function buildDistributables(options) { await run(CleanTypescriptTask); await run(CleanExtraFilesFromModulesTask); await run(CleanEmptyFoldersTask); - await run(CreateStaticFsWithNodeModulesTask); /** * copy generic build outputs into platform-specific build diff --git a/src/dev/build/tasks/create_static_fs_with_node_modules_task.js b/src/dev/build/tasks/create_static_fs_with_node_modules_task.js deleted file mode 100644 index 0ab296fc5c163..0000000000000 --- a/src/dev/build/tasks/create_static_fs_with_node_modules_task.js +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import del from 'del'; -import globby from 'globby'; -import { resolve } from 'path'; -import { generateStaticFsVolume } from '@elastic/static-fs'; - -async function deletePathsList(list) { - for (const path of list) { - await del(path); - } -} - -async function getTopLevelNodeModulesFolders(rootDir) { - const nodeModulesFoldersForCwd = await globby(['**/node_modules', '!**/node_modules/**/*'], { - cwd: rootDir, - onlyDirectories: true, - }); - - return nodeModulesFoldersForCwd.map(folder => resolve(rootDir, folder)); -} - -export const CreateStaticFsWithNodeModulesTask = { - description: - 'Creating static filesystem with node_modules, patching entryPoints and deleting node_modules folder', - - async run(config, log, build) { - const rootDir = build.resolvePath('.'); - - // Get all the top node_modules folders - const nodeModulesFolders = await getTopLevelNodeModulesFolders(rootDir); - - // Define root entry points - const rootEntryPoints = [build.resolvePath('src/setup_node_env/index.js')]; - - // Creates the static filesystem with - // every node_module we have - const staticFsAddedPaths = await generateStaticFsVolume( - rootDir, - nodeModulesFolders, - rootEntryPoints - ); - - // Delete node_modules folder - await deletePathsList(staticFsAddedPaths); - }, -}; diff --git a/src/dev/build/tasks/index.js b/src/dev/build/tasks/index.js index 0232ac4b1b5f3..8105fa8a7d5d4 100644 --- a/src/dev/build/tasks/index.js +++ b/src/dev/build/tasks/index.js @@ -25,7 +25,6 @@ export * from './create_archives_task'; export * from './create_empty_dirs_and_files_task'; export * from './create_package_json_task'; export * from './create_readme_task'; -export * from './create_static_fs_with_node_modules_task'; export * from './install_dependencies_task'; export * from './license_file_task'; export * from './nodejs'; diff --git a/src/plugins/apm_oss/common/index_pattern_constants.ts b/src/plugins/apm_oss/common/index_pattern_constants.ts new file mode 100644 index 0000000000000..4b1800d984ca1 --- /dev/null +++ b/src/plugins/apm_oss/common/index_pattern_constants.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export const APM_STATIC_INDEX_PATTERN_ID = 'apm_static_index_pattern_id'; diff --git a/src/plugins/apm_oss/kibana.json b/src/plugins/apm_oss/kibana.json index 7d9f0652a1139..46fecb09c7fb6 100644 --- a/src/plugins/apm_oss/kibana.json +++ b/src/plugins/apm_oss/kibana.json @@ -6,6 +6,6 @@ "configPath": [ "apm_oss" ], - "ui": false, - "requiredPlugins": [] + "ui": true, + "requiredPlugins": ["home"] } diff --git a/x-pack/plugins/apm/public/assets/apm.png b/src/plugins/apm_oss/public/assets/apm.png similarity index 100% rename from x-pack/plugins/apm/public/assets/apm.png rename to src/plugins/apm_oss/public/assets/apm.png diff --git a/src/plugins/apm_oss/public/index.ts b/src/plugins/apm_oss/public/index.ts new file mode 100644 index 0000000000000..4af80eec4389b --- /dev/null +++ b/src/plugins/apm_oss/public/index.ts @@ -0,0 +1,29 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { ApmOssPlugin } from './plugin'; + +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. +export function plugin() { + return new ApmOssPlugin(); +} +export { ApmOssPluginSetup, ApmOssPluginStart } from './types'; + +export { APM_STATIC_INDEX_PATTERN_ID } from '../common/index_pattern_constants'; diff --git a/src/plugins/apm_oss/public/plugin.ts b/src/plugins/apm_oss/public/plugin.ts new file mode 100644 index 0000000000000..86b2a0abd5ab7 --- /dev/null +++ b/src/plugins/apm_oss/public/plugin.ts @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { CoreSetup, CoreStart, Plugin } from 'kibana/public'; +import { ApmOssPluginSetup, ApmOssPluginStart } from './types'; + +export class ApmOssPlugin implements Plugin { + public setup(core: CoreSetup): ApmOssPluginSetup { + return {}; + } + + public start(core: CoreStart): ApmOssPluginStart { + return {}; + } + + public stop() {} +} diff --git a/src/plugins/apm_oss/public/types.ts b/src/plugins/apm_oss/public/types.ts new file mode 100644 index 0000000000000..96eb2081e372b --- /dev/null +++ b/src/plugins/apm_oss/public/types.ts @@ -0,0 +1,27 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface ApmOssPluginSetup {} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface ApmOssPluginStart {} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface AppPluginStartDependencies {} diff --git a/src/plugins/apm_oss/server/index.ts b/src/plugins/apm_oss/server/index.ts index bd0d23d62500d..d2e7321f39e7b 100644 --- a/src/plugins/apm_oss/server/index.ts +++ b/src/plugins/apm_oss/server/index.ts @@ -17,6 +17,7 @@ * under the License. */ import { schema, TypeOf } from '@kbn/config-schema'; +import apmIndexPattern from './tutorial/index_pattern.json'; import { PluginInitializerContext } from '../../../core/server'; import { APMOSSPlugin } from './plugin'; @@ -40,3 +41,17 @@ export function plugin(initializerContext: PluginInitializerContext) { export type APMOSSConfig = TypeOf; export { APMOSSPluginSetup } from './plugin'; + +export { apmIndexPattern }; + +export { + createNodeAgentInstructions, + createDjangoAgentInstructions, + createFlaskAgentInstructions, + createRailsAgentInstructions, + createRackAgentInstructions, + createJsAgentInstructions, + createGoAgentInstructions, + createJavaAgentInstructions, + createDotNetAgentInstructions, +} from './tutorial/instructions/apm_agent_instructions'; diff --git a/src/plugins/apm_oss/server/plugin.ts b/src/plugins/apm_oss/server/plugin.ts index 9b14d19da90c2..48aed9fa14011 100644 --- a/src/plugins/apm_oss/server/plugin.ts +++ b/src/plugins/apm_oss/server/plugin.ts @@ -18,18 +18,35 @@ */ import { Plugin, CoreSetup, PluginInitializerContext } from 'src/core/server'; import { Observable } from 'rxjs'; +import { take } from 'rxjs/operators'; import { APMOSSConfig } from './'; +import { HomeServerPluginSetup, TutorialProvider } from '../../home/server'; +import { tutorialProvider } from './tutorial'; export class APMOSSPlugin implements Plugin { constructor(private readonly initContext: PluginInitializerContext) { this.initContext = initContext; } - - public setup(core: CoreSetup) { + public async setup(core: CoreSetup, plugins: { home: HomeServerPluginSetup }) { const config$ = this.initContext.config.create(); + const config = await config$.pipe(take(1)).toPromise(); + + const apmTutorialProvider = tutorialProvider({ + indexPatternTitle: config.indexPattern, + indices: { + errorIndices: config.errorIndices, + metricsIndices: config.metricsIndices, + onboardingIndices: config.onboardingIndices, + sourcemapIndices: config.sourcemapIndices, + transactionIndices: config.transactionIndices, + }, + }); + plugins.home.tutorials.registerTutorial(apmTutorialProvider); + return { config$, + getRegisteredTutorialProvider: () => apmTutorialProvider, }; } @@ -39,4 +56,5 @@ export class APMOSSPlugin implements Plugin { export interface APMOSSPluginSetup { config$: Observable; + getRegisteredTutorialProvider(): TutorialProvider; } diff --git a/src/plugins/apm_oss/server/tutorial/envs/on_prem.ts b/src/plugins/apm_oss/server/tutorial/envs/on_prem.ts new file mode 100644 index 0000000000000..477aa36fe3a92 --- /dev/null +++ b/src/plugins/apm_oss/server/tutorial/envs/on_prem.ts @@ -0,0 +1,203 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { INSTRUCTION_VARIANT } from '../../../../home/server'; +import { + createWindowsServerInstructions, + createEditConfig, + createStartServerUnixSysv, + createStartServerUnix, + createDownloadServerRpm, + createDownloadServerDeb, + createDownloadServerOsx, +} from '../instructions/apm_server_instructions'; +import { + createNodeAgentInstructions, + createDjangoAgentInstructions, + createFlaskAgentInstructions, + createRailsAgentInstructions, + createRackAgentInstructions, + createJsAgentInstructions, + createGoAgentInstructions, + createJavaAgentInstructions, + createDotNetAgentInstructions, +} from '../instructions/apm_agent_instructions'; + +export function onPremInstructions({ + errorIndices, + transactionIndices, + metricsIndices, + sourcemapIndices, + onboardingIndices, +}: { + errorIndices: string; + transactionIndices: string; + metricsIndices: string; + sourcemapIndices: string; + onboardingIndices: string; +}) { + const EDIT_CONFIG = createEditConfig(); + const START_SERVER_UNIX = createStartServerUnix(); + const START_SERVER_UNIX_SYSV = createStartServerUnixSysv(); + + return { + instructionSets: [ + { + title: i18n.translate('apmOss.tutorial.apmServer.title', { + defaultMessage: 'APM Server', + }), + callOut: { + title: i18n.translate('apmOss.tutorial.apmServer.callOut.title', { + defaultMessage: 'Important: Updating to 7.0 or higher', + }), + message: i18n.translate('apmOss.tutorial.apmServer.callOut.message', { + defaultMessage: `Please make sure your APM Server is updated to 7.0 or higher. \ + You can also migrate your 6.x data with the migration assistant found in Kibana's management section.`, + }), + iconType: 'alert', + }, + instructionVariants: [ + { + id: INSTRUCTION_VARIANT.OSX, + instructions: [createDownloadServerOsx(), EDIT_CONFIG, START_SERVER_UNIX], + }, + { + id: INSTRUCTION_VARIANT.DEB, + instructions: [createDownloadServerDeb(), EDIT_CONFIG, START_SERVER_UNIX_SYSV], + }, + { + id: INSTRUCTION_VARIANT.RPM, + instructions: [createDownloadServerRpm(), EDIT_CONFIG, START_SERVER_UNIX_SYSV], + }, + { + id: INSTRUCTION_VARIANT.WINDOWS, + instructions: createWindowsServerInstructions(), + }, + ], + statusCheck: { + title: i18n.translate('apmOss.tutorial.apmServer.statusCheck.title', { + defaultMessage: 'APM Server status', + }), + text: i18n.translate('apmOss.tutorial.apmServer.statusCheck.text', { + defaultMessage: + 'Make sure APM Server is running before you start implementing the APM agents.', + }), + btnLabel: i18n.translate('apmOss.tutorial.apmServer.statusCheck.btnLabel', { + defaultMessage: 'Check APM Server status', + }), + success: i18n.translate('apmOss.tutorial.apmServer.statusCheck.successMessage', { + defaultMessage: 'You have correctly setup APM Server', + }), + error: i18n.translate('apmOss.tutorial.apmServer.statusCheck.errorMessage', { + defaultMessage: + 'No APM Server detected. Please make sure it is running and you have updated to 7.0 or higher.', + }), + esHitsCheck: { + index: onboardingIndices, + query: { + bool: { + filter: [ + { term: { 'processor.event': 'onboarding' } }, + { range: { 'observer.version_major': { gte: 7 } } }, + ], + }, + }, + }, + }, + }, + { + title: i18n.translate('apmOss.tutorial.apmAgents.title', { + defaultMessage: 'APM Agents', + }), + instructionVariants: [ + { + id: INSTRUCTION_VARIANT.JAVA, + instructions: createJavaAgentInstructions(), + }, + { + id: INSTRUCTION_VARIANT.JS, + instructions: createJsAgentInstructions(), + }, + { + id: INSTRUCTION_VARIANT.NODE, + instructions: createNodeAgentInstructions(), + }, + { + id: INSTRUCTION_VARIANT.DJANGO, + instructions: createDjangoAgentInstructions(), + }, + { + id: INSTRUCTION_VARIANT.FLASK, + instructions: createFlaskAgentInstructions(), + }, + { + id: INSTRUCTION_VARIANT.RAILS, + instructions: createRailsAgentInstructions(), + }, + { + id: INSTRUCTION_VARIANT.RACK, + instructions: createRackAgentInstructions(), + }, + { + id: INSTRUCTION_VARIANT.GO, + instructions: createGoAgentInstructions(), + }, + { + id: INSTRUCTION_VARIANT.DOTNET, + instructions: createDotNetAgentInstructions(), + }, + ], + statusCheck: { + title: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.title', { + defaultMessage: 'Agent status', + }), + text: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.text', { + defaultMessage: + 'Make sure your application is running and the agents are sending data.', + }), + btnLabel: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.btnLabel', { + defaultMessage: 'Check agent status', + }), + success: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.successMessage', { + defaultMessage: 'Data successfully received from one or more agents', + }), + error: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.errorMessage', { + defaultMessage: 'No data has been received from agents yet', + }), + esHitsCheck: { + index: [errorIndices, transactionIndices, metricsIndices, sourcemapIndices], + query: { + bool: { + filter: [ + { + terms: { + 'processor.event': ['error', 'transaction', 'metric', 'sourcemap'], + }, + }, + { range: { 'observer.version_major': { gte: 7 } } }, + ], + }, + }, + }, + }, + }, + ], + }; +} diff --git a/src/plugins/apm_oss/server/tutorial/index.ts b/src/plugins/apm_oss/server/tutorial/index.ts new file mode 100644 index 0000000000000..aa775d007de30 --- /dev/null +++ b/src/plugins/apm_oss/server/tutorial/index.ts @@ -0,0 +1,93 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { onPremInstructions } from './envs/on_prem'; +import apmIndexPattern from './index_pattern.json'; +import { ArtifactsSchema, TutorialsCategory } from '../../../../../src/plugins/home/server'; +import { APM_STATIC_INDEX_PATTERN_ID } from '../../common/index_pattern_constants'; + +const apmIntro = i18n.translate('apmOss.tutorial.introduction', { + defaultMessage: 'Collect in-depth performance metrics and errors from inside your applications.', +}); + +export const tutorialProvider = ({ + indexPatternTitle, + indices, +}: { + indexPatternTitle: string; + indices: { + errorIndices: string; + transactionIndices: string; + metricsIndices: string; + sourcemapIndices: string; + onboardingIndices: string; + }; +}) => () => { + const savedObjects = [ + { + ...apmIndexPattern, + id: APM_STATIC_INDEX_PATTERN_ID, + attributes: { + ...apmIndexPattern.attributes, + title: indexPatternTitle, + }, + }, + ]; + + const artifacts: ArtifactsSchema = { + dashboards: [ + { + id: '8d3ed660-7828-11e7-8c47-65b845b5cfb3', + linkLabel: i18n.translate('apmOss.tutorial.specProvider.artifacts.dashboards.linkLabel', { + defaultMessage: 'APM dashboard', + }), + isOverview: true, + }, + ], + }; + + return { + id: 'apm', + name: i18n.translate('apmOss.tutorial.specProvider.name', { + defaultMessage: 'APM', + }), + category: TutorialsCategory.OTHER, + shortDescription: apmIntro, + longDescription: i18n.translate('apmOss.tutorial.specProvider.longDescription', { + defaultMessage: + 'Application Performance Monitoring (APM) collects in-depth \ +performance metrics and errors from inside your application. \ +It allows you to monitor the performance of thousands of applications in real time. \ +[Learn more]({learnMoreLink}).', + values: { + learnMoreLink: + '{config.docs.base_url}guide/en/apm/get-started/{config.docs.version}/index.html', + }, + }), + euiIconType: 'apmApp', + artifacts, + onPrem: onPremInstructions(indices), + previewImagePath: '/plugins/apmOss/assets/apm.png', + savedObjects, + savedObjectsInstallMsg: i18n.translate('apmOss.tutorial.specProvider.savedObjectsInstallMsg', { + defaultMessage: 'An APM index pattern is required for some features in the APM UI.', + }), + }; +}; diff --git a/x-pack/plugins/apm/server/tutorial/index_pattern.json b/src/plugins/apm_oss/server/tutorial/index_pattern.json similarity index 100% rename from x-pack/plugins/apm/server/tutorial/index_pattern.json rename to src/plugins/apm_oss/server/tutorial/index_pattern.json diff --git a/src/plugins/apm_oss/server/tutorial/instructions/apm_agent_instructions.ts b/src/plugins/apm_oss/server/tutorial/instructions/apm_agent_instructions.ts new file mode 100644 index 0000000000000..271bcab21172f --- /dev/null +++ b/src/plugins/apm_oss/server/tutorial/instructions/apm_agent_instructions.ts @@ -0,0 +1,663 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; + +export const createNodeAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.nodeClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.nodeClient.install.textPre', { + defaultMessage: 'Install the APM agent for Node.js as a dependency to your application.', + }), + commands: ['npm install elastic-apm-node --save'], + }, + { + title: i18n.translate('apmOss.tutorial.nodeClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('apmOss.tutorial.nodeClient.configure.textPre', { + defaultMessage: + 'Agents are libraries that run inside of your application process. \ +APM services are created programmatically based on the `serviceName`. \ +This agent supports a vararity of frameworks but can also be used with your custom stack.', + }), + commands: `// ${i18n.translate( + 'apmOss.tutorial.nodeClient.configure.commands.addThisToTheFileTopComment', + { + defaultMessage: 'Add this to the VERY top of the first file loaded in your app', + } + )} +var apm = require('elastic-apm-node').start({curlyOpen} + // ${i18n.translate( + 'apmOss.tutorial.nodeClient.configure.commands.setRequiredServiceNameComment', + { + defaultMessage: 'Override service name from package.json', + } + )} + // ${i18n.translate('apmOss.tutorial.nodeClient.configure.commands.allowedCharactersComment', { + defaultMessage: 'Allowed characters: a-z, A-Z, 0-9, -, _, and space', + })} + serviceName: '', + + // ${i18n.translate( + 'apmOss.tutorial.nodeClient.configure.commands.useIfApmRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a token', + } + )} + secretToken: '${secretToken}', + + // ${i18n.translate( + 'apmOss.tutorial.nodeClient.configure.commands.setCustomApmServerUrlComment', + { + defaultMessage: 'Set custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + serverUrl: '${apmServerUrl}' +{curlyClose})`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.nodeClient.configure.textPost', { + defaultMessage: + 'See [the documentation]({documentationLink}) for advanced usage, including how to use with \ +[Babel/ES Modules]({babelEsModulesLink}).', + values: { + documentationLink: '{config.docs.base_url}guide/en/apm/agent/nodejs/current/index.html', + babelEsModulesLink: + '{config.docs.base_url}guide/en/apm/agent/nodejs/current/advanced-setup.html#es-modules', + }, + }), + }, +]; + +export const createDjangoAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.djangoClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.djangoClient.install.textPre', { + defaultMessage: 'Install the APM agent for Python as a dependency.', + }), + commands: ['$ pip install elastic-apm'], + }, + { + title: i18n.translate('apmOss.tutorial.djangoClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('apmOss.tutorial.djangoClient.configure.textPre', { + defaultMessage: + 'Agents are libraries that run inside of your application process. \ +APM services are created programmatically based on the `SERVICE_NAME`.', + }), + commands: `# ${i18n.translate( + 'apmOss.tutorial.djangoClient.configure.commands.addAgentComment', + { + defaultMessage: 'Add the agent to the installed apps', + } + )} +INSTALLED_APPS = ( + 'elasticapm.contrib.django', + # ... +) + +ELASTIC_APM = {curlyOpen} + # ${i18n.translate( + 'apmOss.tutorial.djangoClient.configure.commands.setRequiredServiceNameComment', + { + defaultMessage: 'Set required service name. Allowed characters:', + } + )} + # ${i18n.translate('apmOss.tutorial.djangoClient.configure.commands.allowedCharactersComment', { + defaultMessage: 'a-z, A-Z, 0-9, -, _, and space', + })} + 'SERVICE_NAME': '', + + # ${i18n.translate( + 'apmOss.tutorial.djangoClient.configure.commands.useIfApmServerRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a token', + } + )} + 'SECRET_TOKEN': '${secretToken}', + + # ${i18n.translate( + 'apmOss.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment', + { + defaultMessage: 'Set custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + 'SERVER_URL': '${apmServerUrl}', +{curlyClose} + +# ${i18n.translate('apmOss.tutorial.djangoClient.configure.commands.addTracingMiddlewareComment', { + defaultMessage: 'To send performance metrics, add our tracing middleware:', + })} +MIDDLEWARE = ( + 'elasticapm.contrib.django.middleware.TracingMiddleware', + #... +)`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.djangoClient.configure.textPost', { + defaultMessage: 'See the [documentation]({documentationLink}) for advanced usage.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/python/current/django-support.html', + }, + }), + }, +]; + +export const createFlaskAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.flaskClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.flaskClient.install.textPre', { + defaultMessage: 'Install the APM agent for Python as a dependency.', + }), + commands: ['$ pip install elastic-apm[flask]'], + }, + { + title: i18n.translate('apmOss.tutorial.flaskClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('apmOss.tutorial.flaskClient.configure.textPre', { + defaultMessage: + 'Agents are libraries that run inside of your application process. \ +APM services are created programmatically based on the `SERVICE_NAME`.', + }), + commands: `# ${i18n.translate( + 'apmOss.tutorial.flaskClient.configure.commands.initializeUsingEnvironmentVariablesComment', + { + defaultMessage: 'initialize using environment variables', + } + )} +from elasticapm.contrib.flask import ElasticAPM +app = Flask(__name__) +apm = ElasticAPM(app) + +# ${i18n.translate('apmOss.tutorial.flaskClient.configure.commands.configureElasticApmComment', { + defaultMessage: "or configure to use ELASTIC_APM in your application's settings", + })} +from elasticapm.contrib.flask import ElasticAPM +app.config['ELASTIC_APM'] = {curlyOpen} + # ${i18n.translate( + 'apmOss.tutorial.flaskClient.configure.commands.setRequiredServiceNameComment', + { + defaultMessage: 'Set required service name. Allowed characters:', + } + )} + # ${i18n.translate('apmOss.tutorial.flaskClient.configure.commands.allowedCharactersComment', { + defaultMessage: 'a-z, A-Z, 0-9, -, _, and space', + })} + 'SERVICE_NAME': '', + + # ${i18n.translate( + 'apmOss.tutorial.flaskClient.configure.commands.useIfApmServerRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a token', + } + )} + 'SECRET_TOKEN': '${secretToken}', + + # ${i18n.translate( + 'apmOss.tutorial.flaskClient.configure.commands.setCustomApmServerUrlComment', + { + defaultMessage: 'Set custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + 'SERVER_URL': '${apmServerUrl}', +{curlyClose} + +apm = ElasticAPM(app)`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.flaskClient.configure.textPost', { + defaultMessage: 'See the [documentation]({documentationLink}) for advanced usage.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/python/current/flask-support.html', + }, + }), + }, +]; + +export const createRailsAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.railsClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.railsClient.install.textPre', { + defaultMessage: 'Add the agent to your Gemfile.', + }), + commands: [`gem 'elastic-apm'`], + }, + { + title: i18n.translate('apmOss.tutorial.railsClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('apmOss.tutorial.railsClient.configure.textPre', { + defaultMessage: + 'APM is automatically started when your app boots. Configure the agent, by creating the config file {configFile}', + values: { configFile: '`config/elastic_apm.yml`' }, + }), + commands: `# config/elastic_apm.yml: + +# Set service name - allowed characters: a-z, A-Z, 0-9, -, _ and space +# Defaults to the name of your Rails app +# service_name: 'my-service' + +# Use if APM Server requires a token +# secret_token: '${secretToken}' + +# Set custom APM Server URL (default: http://localhost:8200) +# server_url: '${apmServerUrl || 'http://localhost:8200'}'`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.railsClient.configure.textPost', { + defaultMessage: + 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', + values: { + documentationLink: '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html', + }, + }), + }, +]; + +export const createRackAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.rackClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.rackClient.install.textPre', { + defaultMessage: 'Add the agent to your Gemfile.', + }), + commands: [`gem 'elastic-apm'`], + }, + { + title: i18n.translate('apmOss.tutorial.rackClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('apmOss.tutorial.rackClient.configure.textPre', { + defaultMessage: + 'For Rack or a compatible framework (e.g. Sinatra), include the middleware in your app and start the agent.', + }), + commands: `# config.ru + require 'sinatra/base' + + class MySinatraApp < Sinatra::Base + use ElasticAPM::Middleware + + # ... + end + + ElasticAPM.start( + app: MySinatraApp, # ${i18n.translate( + 'apmOss.tutorial.rackClient.configure.commands.requiredComment', + { + defaultMessage: 'required', + } + )} + config_file: '' # ${i18n.translate( + 'apmOss.tutorial.rackClient.configure.commands.optionalComment', + { + defaultMessage: 'optional, defaults to config/elastic_apm.yml', + } + )} + ) + + run MySinatraApp + + at_exit {curlyOpen} ElasticAPM.stop {curlyClose}`.split('\n'), + }, + { + title: i18n.translate('apmOss.tutorial.rackClient.createConfig.title', { + defaultMessage: 'Create config file', + }), + textPre: i18n.translate('apmOss.tutorial.rackClient.createConfig.textPre', { + defaultMessage: 'Create a config file {configFile}:', + values: { configFile: '`config/elastic_apm.yml`' }, + }), + commands: `# config/elastic_apm.yml: + +# ${i18n.translate('apmOss.tutorial.rackClient.createConfig.commands.setServiceNameComment', { + defaultMessage: 'Set service name - allowed characters: a-z, A-Z, 0-9, -, _ and space', + })} +# ${i18n.translate( + 'apmOss.tutorial.rackClient.createConfig.commands.defaultsToTheNameOfRackAppClassComment', + { + defaultMessage: "Defaults to the name of your Rack app's class.", + } + )} +# service_name: 'my-service' + +# ${i18n.translate( + 'apmOss.tutorial.rackClient.createConfig.commands.useIfApmServerRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a token', + } + )} +# secret_token: '${secretToken}' + +# ${i18n.translate('apmOss.tutorial.rackClient.createConfig.commands.setCustomApmServerComment', { + defaultMessage: 'Set custom APM Server URL (default: {defaultServerUrl})', + values: { defaultServerUrl: 'http://localhost:8200' }, + })} +# server_url: '${apmServerUrl || 'http://localhost:8200'}'`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.rackClient.createConfig.textPost', { + defaultMessage: + 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', + values: { + documentationLink: '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html', + }, + }), + }, +]; + +export const createJsAgentInstructions = (apmServerUrl = '') => [ + { + title: i18n.translate('apmOss.tutorial.jsClient.enableRealUserMonitoring.title', { + defaultMessage: 'Enable Real User Monitoring support in APM Server', + }), + textPre: i18n.translate('apmOss.tutorial.jsClient.enableRealUserMonitoring.textPre', { + defaultMessage: + 'APM Server disables RUM support by default. See the [documentation]({documentationLink}) \ +for details on how to enable RUM support.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/server/{config.docs.version}/configuration-rum.html', + }, + }), + }, + { + title: i18n.translate('apmOss.tutorial.jsClient.installDependency.title', { + defaultMessage: 'Set up the Agent as a dependency', + }), + textPre: i18n.translate('apmOss.tutorial.jsClient.installDependency.textPre', { + defaultMessage: + 'You can install the Agent as a dependency to your application with \ +`npm install @elastic/apm-rum --save`.\n\n\ +The Agent can then be initialized and configured in your application like this:', + }), + commands: `import {curlyOpen} init as initApm {curlyClose} from '@elastic/apm-rum' +var apm = initApm({curlyOpen} + + // ${i18n.translate( + 'apmOss.tutorial.jsClient.installDependency.commands.setRequiredServiceNameComment', + { + defaultMessage: + 'Set required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)', + } + )} + serviceName: 'your-app-name', + + // ${i18n.translate( + 'apmOss.tutorial.jsClient.installDependency.commands.setCustomApmServerUrlComment', + { + defaultMessage: 'Set custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + serverUrl: '${apmServerUrl}', + + // ${i18n.translate( + 'apmOss.tutorial.jsClient.installDependency.commands.setServiceVersionComment', + { + defaultMessage: 'Set service version (required for source map feature)', + } + )} + serviceVersion: '' +{curlyClose})`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.jsClient.installDependency.textPost', { + defaultMessage: + 'Framework integrations, like React or Angular, have custom dependencies. \ +See the [integration documentation]({docLink}) for more information.', + values: { + docLink: + '{config.docs.base_url}guide/en/apm/agent/rum-js/current/framework-integrations.html', + }, + }), + }, + { + title: i18n.translate('apmOss.tutorial.jsClient.scriptTags.title', { + defaultMessage: 'Set up the Agent with Script Tags', + }), + textPre: i18n.translate('apmOss.tutorial.jsClient.scriptTags.textPre', { + defaultMessage: + "Alternatively, you can use Script tags to set up and configure the Agent. \ +Add a ` + +`.split('\n'), + }, +]; + +export const createGoAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.goClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.goClient.install.textPre', { + defaultMessage: 'Install the APM agent packages for Go.', + }), + commands: ['go get go.elastic.co/apm'], + }, + { + title: i18n.translate('apmOss.tutorial.goClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('apmOss.tutorial.goClient.configure.textPre', { + defaultMessage: + 'Agents are libraries that run inside of your application process. \ +APM services are created programmatically based on the executable \ +file name, or the `ELASTIC_APM_SERVICE_NAME` environment variable.', + }), + commands: `# ${i18n.translate( + 'apmOss.tutorial.goClient.configure.commands.initializeUsingEnvironmentVariablesComment', + { + defaultMessage: 'Initialize using environment variables:', + } + )} + +# ${i18n.translate('apmOss.tutorial.goClient.configure.commands.setServiceNameComment', { + defaultMessage: 'Set the service name. Allowed characters: # a-z, A-Z, 0-9, -, _, and space.', + })} +# ${i18n.translate('apmOss.tutorial.goClient.configure.commands.usedExecutableNameComment', { + defaultMessage: + 'If ELASTIC_APM_SERVICE_NAME is not specified, the executable name will be used.', + })} +export ELASTIC_APM_SERVICE_NAME= + +# ${i18n.translate('apmOss.tutorial.goClient.configure.commands.setCustomApmServerUrlComment', { + defaultMessage: 'Set custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + })} +export ELASTIC_APM_SERVER_URL=${apmServerUrl} + +# ${i18n.translate('apmOss.tutorial.goClient.configure.commands.useIfApmRequiresTokenComment', { + defaultMessage: 'Use if APM Server requires a token', + })} +export ELASTIC_APM_SECRET_TOKEN=${secretToken} +`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.goClient.configure.textPost', { + defaultMessage: 'See the [documentation]({documentationLink}) for advanced configuration.', + values: { + documentationLink: '{config.docs.base_url}guide/en/apm/agent/go/current/configuration.html', + }, + }), + }, + { + title: i18n.translate('apmOss.tutorial.goClient.instrument.title', { + defaultMessage: 'Instrument your application', + }), + textPre: i18n.translate('apmOss.tutorial.goClient.instrument.textPre', { + defaultMessage: + 'Instrument your Go application by using one of the provided instrumentation modules or \ +by using the tracer API directly.', + }), + commands: `\ +import ( + "net/http" + + "go.elastic.co/apm/module/apmhttp" +) + +func main() {curlyOpen} + mux := http.NewServeMux() + ... + http.ListenAndServe(":8080", apmhttp.Wrap(mux)) +{curlyClose} +`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.goClient.instrument.textPost', { + defaultMessage: + 'See the [documentation]({documentationLink}) for a detailed \ +guide to instrumenting Go source code.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/go/current/instrumenting-source.html', + }, + }), + }, +]; + +export const createJavaAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.javaClient.download.title', { + defaultMessage: 'Download the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.javaClient.download.textPre', { + defaultMessage: + 'Download the agent jar from [Maven Central]({mavenCentralLink}). \ +Do **not** add the agent as a dependency to your application.', + values: { + mavenCentralLink: 'http://search.maven.org/#search%7Cga%7C1%7Ca%3Aelastic-apm-agent', + }, + }), + }, + { + title: i18n.translate('apmOss.tutorial.javaClient.startApplication.title', { + defaultMessage: 'Start your application with the javaagent flag', + }), + textPre: i18n.translate('apmOss.tutorial.javaClient.startApplication.textPre', { + defaultMessage: + 'Add the `-javaagent` flag and configure the agent with system properties.\n\n \ +* Set required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)\n \ +* Set custom APM Server URL (default: {customApmServerUrl})\n \ +* Set the base package of your application', + values: { customApmServerUrl: 'http://localhost:8200' }, + }), + commands: `java -javaagent:/path/to/elastic-apm-agent-.jar \\ + -Delastic.apm.service_name=my-application \\ + -Delastic.apm.server_urls=${apmServerUrl || 'http://localhost:8200'} \\ + -Delastic.apm.secret_token=${secretToken} \\ + -Delastic.apm.application_packages=org.example \\ + -jar my-application.jar`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.javaClient.startApplication.textPost', { + defaultMessage: + 'See the [documentation]({documentationLink}) for configuration options and advanced \ +usage.', + values: { + documentationLink: '{config.docs.base_url}guide/en/apm/agent/java/current/index.html', + }, + }), + }, +]; + +export const createDotNetAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.dotNetClient.download.title', { + defaultMessage: 'Download the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.dotNetClient.download.textPre', { + defaultMessage: + 'Add the the agent package(s) from [NuGet]({allNuGetPackagesLink}) to your .NET application. There are multiple \ + NuGet packages available for different use cases. \n\nFor an ASP.NET Core application with Entity Framework \ + Core download the [Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink}) package. This package will automatically add every \ + agent component to your application. \n\n In case you would like to to minimize the dependencies, you can use the \ + [Elastic.Apm.AspNetCore]({aspNetCorePackageLink}) package for just \ + ASP.NET Core monitoring or the [Elastic.Apm.EfCore]({efCorePackageLink}) package for just Entity Framework Core monitoring. \n\n \ + In case you only want to use the public Agent API for manual instrumentation use the [Elastic.Apm]({elasticApmPackageLink}) package.', + values: { + allNuGetPackagesLink: 'https://www.nuget.org/packages?q=Elastic.apm', + netCoreAllApmPackageLink: 'https://www.nuget.org/packages/Elastic.Apm.NetCoreAll', + aspNetCorePackageLink: 'https://www.nuget.org/packages/Elastic.Apm.AspNetCore', + efCorePackageLink: 'https://www.nuget.org/packages/Elastic.Apm.EntityFrameworkCore', + elasticApmPackageLink: 'https://www.nuget.org/packages/Elastic.Apm', + }, + }), + }, + { + title: i18n.translate('apmOss.tutorial.dotNetClient.configureApplication.title', { + defaultMessage: 'Add the agent to the application', + }), + textPre: i18n.translate('apmOss.tutorial.dotNetClient.configureApplication.textPre', { + defaultMessage: + 'In case of ASP.NET Core with the `Elastic.Apm.NetCoreAll` package, call the `UseAllElasticApm` \ + method in the `Configure` method within the `Startup.cs` file.', + }), + commands: `public class Startup +{curlyOpen} + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + {curlyOpen} + app.UseAllElasticApm(Configuration); + //…rest of the method + {curlyClose} + //…rest of the class +{curlyClose}`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.dotNetClient.configureApplication.textPost', { + defaultMessage: + 'Passing an `IConfiguration` instance is optional and by doing so, the agent will read config settings through this \ + `IConfiguration` instance (e.g. from the `appsettings.json` file).', + }), + }, + { + title: i18n.translate('apmOss.tutorial.dotNetClient.configureAgent.title', { + defaultMessage: 'Sample appsettings.json file:', + }), + commands: `{curlyOpen} + "ElasticApm": {curlyOpen} + "SecretToken": "${secretToken}", + "ServerUrls": "${apmServerUrl || + 'http://localhost:8200'}", //Set custom APM Server URL (default: http://localhost:8200) + "ServiceName" : "MyApp", //allowed characters: a-z, A-Z, 0-9, -, _, and space. Default is the entry assembly of the application + {curlyClose} +{curlyClose}`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.dotNetClient.configureAgent.textPost', { + defaultMessage: + 'In case you don’t pass an `IConfiguration` instance to the agent (e.g. in case of non ASP.NET Core applications) \ + you can also configure the agent through environment variables. \n \ + See [the documentation]({documentationLink}) for advanced usage.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/dotnet/current/configuration.html', + }, + }), + }, +]; diff --git a/src/plugins/apm_oss/server/tutorial/instructions/apm_server_instructions.ts b/src/plugins/apm_oss/server/tutorial/instructions/apm_server_instructions.ts new file mode 100644 index 0000000000000..228c4f02ac9e8 --- /dev/null +++ b/src/plugins/apm_oss/server/tutorial/instructions/apm_server_instructions.ts @@ -0,0 +1,151 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; + +export const createEditConfig = () => ({ + title: i18n.translate('apmOss.tutorial.editConfig.title', { + defaultMessage: 'Edit the configuration', + }), + textPre: i18n.translate('apmOss.tutorial.editConfig.textPre', { + defaultMessage: + "If you're using an X-Pack secured version of Elastic Stack, you must specify \ +credentials in the `apm-server.yml` config file.", + }), + commands: [ + 'output.elasticsearch:', + ' hosts: [""]', + ' username: ', + ' password: ', + ], +}); + +const createStartServer = () => ({ + title: i18n.translate('apmOss.tutorial.startServer.title', { + defaultMessage: 'Start APM Server', + }), + textPre: i18n.translate('apmOss.tutorial.startServer.textPre', { + defaultMessage: + 'The server processes and stores application performance metrics in Elasticsearch.', + }), +}); + +export function createStartServerUnixSysv() { + const START_SERVER = createStartServer(); + + return { + title: START_SERVER.title, + textPre: START_SERVER.textPre, + commands: ['service apm-server start'], + }; +} + +export function createStartServerUnix() { + const START_SERVER = createStartServer(); + + return { + title: START_SERVER.title, + textPre: START_SERVER.textPre, + commands: ['./apm-server -e'], + }; +} + +const createDownloadServerTitle = () => + i18n.translate('apmOss.tutorial.downloadServer.title', { + defaultMessage: 'Download and unpack APM Server', + }); + +export const createDownloadServerOsx = () => ({ + title: createDownloadServerTitle(), + commands: [ + 'curl -L -O https://artifacts.elastic.co/downloads/apm-server/apm-server-{config.kibana.version}-darwin-x86_64.tar.gz', + 'tar xzvf apm-server-{config.kibana.version}-darwin-x86_64.tar.gz', + 'cd apm-server-{config.kibana.version}-darwin-x86_64/', + ], +}); + +export const createDownloadServerDeb = () => ({ + title: createDownloadServerTitle(), + commands: [ + 'curl -L -O https://artifacts.elastic.co/downloads/apm-server/apm-server-{config.kibana.version}-amd64.deb', + 'sudo dpkg -i apm-server-{config.kibana.version}-amd64.deb', + ], + textPost: i18n.translate('apmOss.tutorial.downloadServerTitle', { + defaultMessage: 'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).', + values: { + downloadPageLink: '{config.docs.base_url}downloads/apm/apm-server', + }, + }), +}); + +export const createDownloadServerRpm = () => ({ + title: createDownloadServerTitle(), + commands: [ + 'curl -L -O https://artifacts.elastic.co/downloads/apm-server/apm-server-{config.kibana.version}-x86_64.rpm', + 'sudo rpm -vi apm-server-{config.kibana.version}-x86_64.rpm', + ], + textPost: i18n.translate('apmOss.tutorial.downloadServerRpm', { + defaultMessage: 'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).', + values: { + downloadPageLink: '{config.docs.base_url}downloads/apm/apm-server', + }, + }), +}); + +export function createWindowsServerInstructions() { + const START_SERVER = createStartServer(); + + return [ + { + title: createDownloadServerTitle(), + textPre: i18n.translate('apmOss.tutorial.windowsServerInstructions.textPre', { + defaultMessage: + '1. Download the APM Server Windows zip file from the \ +[Download page]({downloadPageLink}).\n2. Extract the contents of \ +the zip file into {zipFileExtractFolder}.\n3. Rename the {apmServerDirectory} \ +directory to `APM-Server`.\n4. Open a PowerShell prompt as an Administrator \ +(right-click the PowerShell icon and select \ +**Run As Administrator**). If you are running Windows XP, you might need to download and install \ +PowerShell.\n5. From the PowerShell prompt, run the following commands to install APM Server as a Windows service:', + values: { + downloadPageLink: 'https://www.elastic.co/downloads/apm/apm-server', + zipFileExtractFolder: '`C:\\Program Files`', + apmServerDirectory: '`apm-server-{config.kibana.version}-windows`', + }, + }), + commands: [`cd 'C:\\Program Files\\APM-Server'`, `.\\install-service-apm-server.ps1`], + textPost: i18n.translate('apmOss.tutorial.windowsServerInstructions.textPost', { + defaultMessage: + 'Note: If script execution is disabled on your system, \ +you need to set the execution policy for the current session \ +to allow the script to run. For example: {command}.', + values: { + command: + '`PowerShell.exe -ExecutionPolicy UnRestricted -File .\\install-service-apm-server.ps1`', + }, + }), + }, + createEditConfig(), + { + title: START_SERVER.title, + textPre: START_SERVER.textPre, + commands: ['Start-Service apm-server'], + }, + ]; +} diff --git a/src/plugins/home/server/services/tutorials/tutorials_registry.mock.ts b/src/plugins/home/server/services/tutorials/tutorials_registry.mock.ts index b54b0be4ea2b7..5ff0152062f4b 100644 --- a/src/plugins/home/server/services/tutorials/tutorials_registry.mock.ts +++ b/src/plugins/home/server/services/tutorials/tutorials_registry.mock.ts @@ -26,6 +26,7 @@ import { const createSetupMock = (): jest.Mocked => { const setup = { registerTutorial: jest.fn(), + unregisterTutorial: jest.fn(), addScopedTutorialContextFactory: jest.fn(), }; return setup; diff --git a/src/plugins/home/server/services/tutorials/tutorials_registry.ts b/src/plugins/home/server/services/tutorials/tutorials_registry.ts index e820924d7608d..ed28e42dbcf99 100644 --- a/src/plugins/home/server/services/tutorials/tutorials_registry.ts +++ b/src/plugins/home/server/services/tutorials/tutorials_registry.ts @@ -28,7 +28,7 @@ import { tutorialSchema } from './lib/tutorial_schema'; import { builtInTutorials } from '../../tutorials/register'; export class TutorialsRegistry { - private readonly tutorialProviders: TutorialProvider[] = []; // pre-register all the tutorials we know we want in here + private tutorialProviders: TutorialProvider[] = []; // pre-register all the tutorials we know we want in here private readonly scopedTutorialContextFactories: TutorialContextFactory[] = []; public setup(core: CoreSetup) { @@ -63,6 +63,12 @@ export class TutorialsRegistry { this.tutorialProviders.push(specProvider); }, + unregisterTutorial: (specProvider: TutorialProvider) => { + this.tutorialProviders = this.tutorialProviders.filter( + provider => provider !== specProvider + ); + }, + addScopedTutorialContextFactory: ( scopedTutorialContextFactory: ScopedTutorialContextFactory ) => { diff --git a/src/plugins/vis_default_editor/public/default_editor.tsx b/src/plugins/vis_default_editor/public/default_editor.tsx index 8088921ba7fda..43d097345001e 100644 --- a/src/plugins/vis_default_editor/public/default_editor.tsx +++ b/src/plugins/vis_default_editor/public/default_editor.tsx @@ -17,16 +17,23 @@ * under the License. */ +import './index.scss'; + import React, { useEffect, useRef, useState, useCallback } from 'react'; import { EditorRenderProps } from 'src/plugins/visualize/public'; -import { PanelsContainer, Panel } from '../../kibana_react/public'; +import { KibanaContextProvider, PanelsContainer, Panel } from '../../kibana_react/public'; +import { Storage } from '../../kibana_utils/public'; import { DefaultEditorSideBar } from './components/sidebar'; import { DefaultEditorControllerState } from './default_editor_controller'; import { getInitialWidth } from './editor_size'; +const localStorage = new Storage(window.localStorage); + function DefaultEditor({ + core, + data, vis, uiState, timeRange, @@ -37,7 +44,7 @@ function DefaultEditor({ eventEmitter, linked, savedSearch, -}: DefaultEditorControllerState & Omit) { +}: DefaultEditorControllerState & EditorRenderProps) { const visRef = useRef(null); const [isCollapsed, setIsCollapsed] = useState(false); @@ -69,34 +76,49 @@ function DefaultEditor({ const editorInitialWidth = getInitialWidth(vis.type.editorConfig.defaultSize); return ( - - -
- - - + - - - + + +
+ + + + + + + + ); } -export { DefaultEditor }; +// default export required for React.Lazy +// eslint-disable-next-line import/no-default-export +export { DefaultEditor as default }; diff --git a/src/plugins/vis_default_editor/public/default_editor_controller.tsx b/src/plugins/vis_default_editor/public/default_editor_controller.tsx index 014c69f50d558..3158582438558 100644 --- a/src/plugins/vis_default_editor/public/default_editor_controller.tsx +++ b/src/plugins/vis_default_editor/public/default_editor_controller.tsx @@ -17,19 +17,17 @@ * under the License. */ -import React from 'react'; +import React, { Suspense, lazy } from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { i18n } from '@kbn/i18n'; import { EventEmitter } from 'events'; +import { EuiErrorBoundary, EuiLoadingChart } from '@elastic/eui'; import { EditorRenderProps } from 'src/plugins/visualize/public'; import { Vis, VisualizeEmbeddableContract } from 'src/plugins/visualizations/public'; -import { Storage } from '../../kibana_utils/public'; -import { KibanaContextProvider } from '../../kibana_react/public'; -import { DefaultEditor } from './default_editor'; import { DefaultEditorDataTab, OptionTab } from './components/sidebar'; -const localStorage = new Storage(window.localStorage); +const DefaultEditor = lazy(() => import('./default_editor')); export interface DefaultEditorControllerState { vis: Vis; @@ -80,20 +78,26 @@ class DefaultEditorController { }; } - render({ data, core, ...props }: EditorRenderProps) { + render(props: EditorRenderProps) { render( - - + + +
+ } > - - , + + , this.el ); } diff --git a/src/plugins/vis_default_editor/public/index.scss b/src/plugins/vis_default_editor/public/index.scss index ec51ee8bd5780..6abb45dc546a3 100644 --- a/src/plugins/vis_default_editor/public/index.scss +++ b/src/plugins/vis_default_editor/public/index.scss @@ -1,5 +1,3 @@ -@import 'src/legacy/ui/public/styles/styling_constants'; - $vis-editor-sidebar-min-width: 350px; // Main layout diff --git a/src/plugins/vis_default_editor/public/index.ts b/src/plugins/vis_default_editor/public/index.ts index 6c58c6df26b00..156d50f451b57 100644 --- a/src/plugins/vis_default_editor/public/index.ts +++ b/src/plugins/vis_default_editor/public/index.ts @@ -17,8 +17,6 @@ * under the License. */ -import './index.scss'; - export { DefaultEditorController } from './default_editor_controller'; export { useValidation } from './components/controls/utils'; export { RangesParamEditor, RangeValues } from './components/controls/ranges'; diff --git a/src/plugins/vis_type_timelion/server/routes/run.ts b/src/plugins/vis_type_timelion/server/routes/run.ts index b773bba68ea81..1efc7c4101518 100644 --- a/src/plugins/vis_type_timelion/server/routes/run.ts +++ b/src/plugins/vis_type_timelion/server/routes/run.ts @@ -31,30 +31,6 @@ import { ConfigManager } from '../lib/config_manager'; const timelionDefaults = getNamespacesSettings(); -export interface TimelionRequestQuery { - payload: { - sheet: string[]; - extended?: { - es: { - filter: { - bool: { - filter: string[] | object; - must: string[]; - should: string[]; - must_not: string[]; - }; - }; - }; - }; - }; - time?: { - from?: string; - interval: string; - timezone: string; - to?: string; - }; -} - export function runRoute( router: IRouter, { diff --git a/src/plugins/vis_type_timelion/server/series_functions/es/es.test.js b/src/plugins/vis_type_timelion/server/series_functions/es/es.test.js index 4bd37b03f01fe..56d4b6812d3d9 100644 --- a/src/plugins/vis_type_timelion/server/series_functions/es/es.test.js +++ b/src/plugins/vis_type_timelion/server/series_functions/es/es.test.js @@ -239,7 +239,7 @@ describe('es', () => { to: 5, }, request: { - payload: { + body: { extended: { es: { filter: { @@ -258,7 +258,7 @@ describe('es', () => { }); }); - it('adds the contents of payload.extended.es.filter to a filter clause of the bool', () => { + it('adds the contents of body.extended.es.filter to a filter clause of the bool', () => { config.kibana = true; const request = fn(config, tlConfig, emptyScriptedFields); const filter = request.body.query.bool.filter.bool; diff --git a/src/plugins/vis_type_timelion/server/series_functions/es/lib/build_request.js b/src/plugins/vis_type_timelion/server/series_functions/es/lib/build_request.js index 2149e44125be0..38618ccf66d6f 100644 --- a/src/plugins/vis_type_timelion/server/series_functions/es/lib/build_request.js +++ b/src/plugins/vis_type_timelion/server/series_functions/es/lib/build_request.js @@ -38,7 +38,7 @@ export default function buildRequest(config, tlConfig, scriptedFields, timeout) // Use the kibana filter bar filters if (config.kibana) { - bool.filter = _.get(tlConfig, 'request.payload.extended.es.filter'); + bool.filter = _.get(tlConfig, 'request.body.extended.es.filter'); } const aggs = { diff --git a/src/plugins/vis_type_timelion/server/types.ts b/src/plugins/vis_type_timelion/server/types.ts index a035d64f764f1..9fc8734a560b7 100644 --- a/src/plugins/vis_type_timelion/server/types.ts +++ b/src/plugins/vis_type_timelion/server/types.ts @@ -18,4 +18,3 @@ */ export { TimelionFunctionInterface, TimelionFunctionConfig } from './lib/classes/timelion_function'; -export { TimelionRequestQuery } from './routes/run'; diff --git a/src/plugins/vis_type_timeseries/public/application/lib/validate_interval.js b/src/plugins/vis_type_timeseries/public/application/lib/validate_interval.js index 40fd4d871a96a..e8ddb4ceb5cba 100644 --- a/src/plugins/vis_type_timeseries/public/application/lib/validate_interval.js +++ b/src/plugins/vis_type_timeseries/public/application/lib/validate_interval.js @@ -40,8 +40,7 @@ export function validateInterval(bounds, panel, maxBuckets) { 'visTypeTimeseries.validateInterval.notifier.maxBucketsExceededErrorMessage', { defaultMessage: - 'Max buckets exceeded: {buckets} is greater than {maxBuckets}, try a larger time interval in the panel options.', - values: { buckets, maxBuckets }, + 'Your query attempted to fetch too much data. Reducing the time range or changing the interval used usually fixes the issue.', } ) ); diff --git a/src/plugins/visualize/public/application/editor/visualization_editor.js b/src/plugins/visualize/public/application/editor/visualization_editor.js index 874b69532ec11..381148651a46b 100644 --- a/src/plugins/visualize/public/application/editor/visualization_editor.js +++ b/src/plugins/visualize/public/application/editor/visualization_editor.js @@ -17,6 +17,8 @@ * under the License. */ +import { DefaultEditorController } from '../../../../vis_default_editor/public'; + export function initVisEditorDirective(app, deps) { app.directive('visualizationEditor', function($timeout) { return { @@ -32,7 +34,7 @@ export function initVisEditorDirective(app, deps) { eventEmitter: '=', }, link: function($scope, element) { - const Editor = $scope.vis.type.editor || deps.DefaultVisualizationEditor; + const Editor = $scope.vis.type.editor || DefaultEditorController; const editor = new Editor( element[0], $scope.vis, diff --git a/src/plugins/visualize/public/kibana_services.ts b/src/plugins/visualize/public/kibana_services.ts index ace9e50d400c5..8d714f1844345 100644 --- a/src/plugins/visualize/public/kibana_services.ts +++ b/src/plugins/visualize/public/kibana_services.ts @@ -34,7 +34,6 @@ import { DataPublicPluginStart } from '../../data/public'; import { VisualizationsStart } from '../../visualizations/public'; import { SavedVisualizations } from './application/types'; import { KibanaLegacyStart } from '../../kibana_legacy/public'; -import { DefaultEditorController } from '../../vis_default_editor/public'; import { DashboardStart } from '../../dashboard/public'; import { SavedObjectsStart } from '../../saved_objects/public'; @@ -56,7 +55,6 @@ export interface VisualizeKibanaServices { dashboard: DashboardStart; I18nContext: I18nStart['Context']; setActiveUrl: (newUrl: string) => void; - DefaultVisualizationEditor: typeof DefaultEditorController; createVisEmbeddableFromObject: VisualizationsStart['__LEGACY']['createVisEmbeddableFromObject']; scopedHistory: () => ScopedHistory; savedObjects: SavedObjectsStart; diff --git a/src/plugins/visualize/public/plugin.ts b/src/plugins/visualize/public/plugin.ts index 9d1e89a024b61..8a104dc51feb4 100644 --- a/src/plugins/visualize/public/plugin.ts +++ b/src/plugins/visualize/public/plugin.ts @@ -40,7 +40,6 @@ import { VisualizationsStart } from '../../visualizations/public'; import { VisualizeConstants } from './application/visualize_constants'; import { setServices, VisualizeKibanaServices } from './kibana_services'; import { FeatureCatalogueCategory, HomePublicPluginSetup } from '../../home/public'; -import { DefaultEditorController } from '../../vis_default_editor/public'; import { DashboardStart } from '../../dashboard/public'; import { DEFAULT_APP_CATEGORIES } from '../../../core/public'; import { SavedObjectsStart } from '../../saved_objects/public'; @@ -132,7 +131,6 @@ export class VisualizePlugin visualizations: pluginsStart.visualizations, I18nContext: coreStart.i18n.Context, setActiveUrl, - DefaultVisualizationEditor: DefaultEditorController, createVisEmbeddableFromObject: pluginsStart.visualizations.__LEGACY.createVisEmbeddableFromObject, dashboard: pluginsStart.dashboard, diff --git a/x-pack/dev-tools/jest/create_jest_config.js b/x-pack/dev-tools/jest/create_jest_config.js index 75f8a3c156e01..3d8b45e7d1b83 100644 --- a/x-pack/dev-tools/jest/create_jest_config.js +++ b/x-pack/dev-tools/jest/create_jest_config.js @@ -18,6 +18,7 @@ export function createJestConfig({ kibanaDirectory, xPackKibanaDirectory }) { 'uiExports/(.*)': fileMockPath, '^src/core/(.*)': `${kibanaDirectory}/src/core/$1`, '^src/legacy/(.*)': `${kibanaDirectory}/src/legacy/$1`, + '^src/plugins/(.*)': `${kibanaDirectory}/src/plugins/$1`, '^plugins/([^/.]*)(.*)': `${kibanaDirectory}/src/legacy/core_plugins/$1/public$2`, '^legacy/plugins/xpack_main/(.*);': `${xPackKibanaDirectory}/legacy/plugins/xpack_main/public/$1`, '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': fileMockPath, diff --git a/x-pack/legacy/plugins/security/index.ts b/x-pack/legacy/plugins/security/index.ts index b1dec2ce82c52..577b23f3418e8 100644 --- a/x-pack/legacy/plugins/security/index.ts +++ b/x-pack/legacy/plugins/security/index.ts @@ -72,14 +72,6 @@ export const security = (kibana: Record) => auditLogger: new AuditLogger(server, 'security', server.config(), xpackInfo), }); - // Legacy xPack Info endpoint returns whatever we return in a callback for `registerLicenseCheckResultsGenerator` - // and the result is consumed by the legacy plugins all over the place, so we should keep it here for now. We assume - // that when legacy callback is called license has been already propagated to the new platform security plugin and - // features are up to date. - xpackInfo - .feature(this.id) - .registerLicenseCheckResultsGenerator(() => securityPlugin.license.getFeatures()); - server.expose({ getUser: async (request: LegacyRequest) => securityPlugin.authc.getCurrentUser(KibanaRequest.from(request)), diff --git a/x-pack/legacy/plugins/xpack_main/server/lib/__tests__/replace_injected_vars.js b/x-pack/legacy/plugins/xpack_main/server/lib/__tests__/replace_injected_vars.js index ae929045cf570..cb70a7cb446a9 100644 --- a/x-pack/legacy/plugins/xpack_main/server/lib/__tests__/replace_injected_vars.js +++ b/x-pack/legacy/plugins/xpack_main/server/lib/__tests__/replace_injected_vars.js @@ -177,16 +177,6 @@ describe('replaceInjectedVars uiExport', () => { }, }); }); - - it('sends the originalInjectedVars if the license check result is not available', async () => { - const originalInjectedVars = { a: 1 }; - const request = buildRequest(); - const server = mockServer(); - server.plugins.xpack_main.info.feature().getLicenseCheckResults.returns(undefined); - - const newVars = await replaceInjectedVars(originalInjectedVars, request, server); - expect(newVars).to.eql(originalInjectedVars); - }); }); // creates a mock server object that defaults to being authenticated with a diff --git a/x-pack/legacy/plugins/xpack_main/server/lib/replace_injected_vars.js b/x-pack/legacy/plugins/xpack_main/server/lib/replace_injected_vars.js index 403bb4e2b334c..f09f97d44bfe8 100644 --- a/x-pack/legacy/plugins/xpack_main/server/lib/replace_injected_vars.js +++ b/x-pack/legacy/plugins/xpack_main/server/lib/replace_injected_vars.js @@ -20,7 +20,7 @@ export async function replaceInjectedVars(originalInjectedVars, request, server) } // not enough license info to make decision one way or another - if (!xpackInfo.isAvailable() || !xpackInfo.feature('security').getLicenseCheckResults()) { + if (!xpackInfo.isAvailable()) { return originalInjectedVars; } diff --git a/x-pack/package.json b/x-pack/package.json index 46993f629c069..fa644f0abe646 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -106,7 +106,7 @@ "@types/redux-actions": "^2.6.1", "@types/set-value": "^2.0.0", "@types/sinon": "^7.0.13", - "@types/styled-components": "^4.4.2", + "@types/styled-components": "^5.1.0", "@types/supertest": "^2.0.5", "@types/tar-fs": "^1.16.1", "@types/tinycolor2": "^1.4.1", @@ -149,7 +149,7 @@ "hoist-non-react-statics": "^3.3.2", "jest": "^24.9.0", "jest-cli": "^24.9.0", - "jest-styled-components": "^7.0.0", + "jest-styled-components": "^7.0.2", "jsdom": "^15.2.1", "loader-utils": "^1.2.3", "madge": "3.4.4", @@ -318,7 +318,7 @@ "react-dom": "^16.12.0", "react-dropzone": "^4.2.9", "react-fast-compare": "^2.0.4", - "react-markdown": "^3.4.1", + "react-markdown": "^4.3.1", "react-moment-proptypes": "^1.7.0", "react-portal": "^3.2.0", "react-redux": "^7.1.3", @@ -350,7 +350,7 @@ "squel": "^5.13.0", "stats-lite": "^2.2.0", "style-it": "^2.1.3", - "styled-components": "^5.0.0", + "styled-components": "^5.1.0", "suricata-sid-db": "^1.0.2", "tinycolor2": "1.4.1", "tinymath": "1.2.1", diff --git a/x-pack/plugins/apm/common/index_pattern_constants.ts b/x-pack/plugins/apm/common/index_pattern_constants.ts deleted file mode 100644 index bedda56452e0a..0000000000000 --- a/x-pack/plugins/apm/common/index_pattern_constants.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export const APM_STATIC_INDEX_PATTERN_ID = 'apm_static_index_pattern_id'; diff --git a/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx index a80d1338dd7be..8c3e2c2396cbd 100644 --- a/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx @@ -11,7 +11,7 @@ import url from 'url'; import rison, { RisonValue } from 'rison-node'; import { useLocation } from '../../../../hooks/useLocation'; import { getTimepickerRisonData } from '../rison_helpers'; -import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../common/index_pattern_constants'; +import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../../../../src/plugins/apm_oss/public'; import { useApmPluginContext } from '../../../../hooks/useApmPluginContext'; import { AppMountContextBasePath } from '../../../../context/ApmPluginContext'; diff --git a/x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/__snapshots__/Stackframe.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/__snapshots__/Stackframe.test.tsx.snap index 4177b54f20385..0656134e2f1fc 100644 --- a/x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/__snapshots__/Stackframe.test.tsx.snap +++ b/x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/__snapshots__/Stackframe.test.tsx.snap @@ -383,8 +383,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "$$typeof": Symbol(react.forward_ref), "attrs": Array [], "componentStyle": ComponentStyle { - "baseHash": 573909505, - "componentId": "sc-fzXfLO", + "baseHash": 1280172402, + "componentId": "sc-fzozJi", "isStatic": false, "rules": Array [ " @@ -400,7 +400,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "displayName": "styled.code", "foldedComponentIds": Array [], "render": [Function], - "styledComponentId": "sc-fzXfLO", + "shouldForwardProp": undefined, + "styledComponentId": "sc-fzozJi", "target": "code", "toString": [Function], "warnTooManyClasses": [Function], @@ -412,8 +413,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "$$typeof": Symbol(react.forward_ref), "attrs": Array [], "componentStyle": ComponentStyle { - "baseHash": 3487560131, - "componentId": "sc-AykKK", + "baseHash": -1923298833, + "componentId": "sc-AxmLO", "isStatic": false, "rules": Array [ " @@ -437,7 +438,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "displayName": "styled.pre", "foldedComponentIds": Array [], "render": [Function], - "styledComponentId": "sc-AykKK", + "shouldForwardProp": undefined, + "styledComponentId": "sc-AxmLO", "target": "pre", "toString": [Function], "warnTooManyClasses": [Function], @@ -606,8 +608,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "$$typeof": Symbol(react.forward_ref), "attrs": Array [], "componentStyle": ComponentStyle { - "baseHash": 573909505, - "componentId": "sc-fzXfLO", + "baseHash": 1280172402, + "componentId": "sc-fzozJi", "isStatic": false, "rules": Array [ " @@ -623,7 +625,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "displayName": "styled.code", "foldedComponentIds": Array [], "render": [Function], - "styledComponentId": "sc-fzXfLO", + "shouldForwardProp": undefined, + "styledComponentId": "sc-fzozJi", "target": "code", "toString": [Function], "warnTooManyClasses": [Function], @@ -635,8 +638,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "$$typeof": Symbol(react.forward_ref), "attrs": Array [], "componentStyle": ComponentStyle { - "baseHash": 3487560131, - "componentId": "sc-AykKK", + "baseHash": -1923298833, + "componentId": "sc-AxmLO", "isStatic": false, "rules": Array [ " @@ -660,7 +663,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "displayName": "styled.pre", "foldedComponentIds": Array [], "render": [Function], - "styledComponentId": "sc-AykKK", + "shouldForwardProp": undefined, + "styledComponentId": "sc-AxmLO", "target": "pre", "toString": [Function], "warnTooManyClasses": [Function], @@ -830,8 +834,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "$$typeof": Symbol(react.forward_ref), "attrs": Array [], "componentStyle": ComponentStyle { - "baseHash": 573909505, - "componentId": "sc-fzXfLO", + "baseHash": 1280172402, + "componentId": "sc-fzozJi", "isStatic": false, "rules": Array [ " @@ -847,7 +851,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "displayName": "styled.code", "foldedComponentIds": Array [], "render": [Function], - "styledComponentId": "sc-fzXfLO", + "shouldForwardProp": undefined, + "styledComponentId": "sc-fzozJi", "target": "code", "toString": [Function], "warnTooManyClasses": [Function], @@ -859,8 +864,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "$$typeof": Symbol(react.forward_ref), "attrs": Array [], "componentStyle": ComponentStyle { - "baseHash": 3487560131, - "componentId": "sc-AykKK", + "baseHash": -1923298833, + "componentId": "sc-AxmLO", "isStatic": false, "rules": Array [ " @@ -884,7 +889,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "displayName": "styled.pre", "foldedComponentIds": Array [], "render": [Function], - "styledComponentId": "sc-AykKK", + "shouldForwardProp": undefined, + "styledComponentId": "sc-AxmLO", "target": "pre", "toString": [Function], "warnTooManyClasses": [Function], @@ -1064,8 +1070,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "$$typeof": Symbol(react.forward_ref), "attrs": Array [], "componentStyle": ComponentStyle { - "baseHash": 573909505, - "componentId": "sc-fzXfLO", + "baseHash": 1280172402, + "componentId": "sc-fzozJi", "isStatic": false, "rules": Array [ " @@ -1081,7 +1087,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "displayName": "styled.code", "foldedComponentIds": Array [], "render": [Function], - "styledComponentId": "sc-fzXfLO", + "shouldForwardProp": undefined, + "styledComponentId": "sc-fzozJi", "target": "code", "toString": [Function], "warnTooManyClasses": [Function], @@ -1093,8 +1100,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "$$typeof": Symbol(react.forward_ref), "attrs": Array [], "componentStyle": ComponentStyle { - "baseHash": 3487560131, - "componentId": "sc-AykKK", + "baseHash": -1923298833, + "componentId": "sc-AxmLO", "isStatic": false, "rules": Array [ " @@ -1118,7 +1125,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "displayName": "styled.pre", "foldedComponentIds": Array [], "render": [Function], - "styledComponentId": "sc-AykKK", + "shouldForwardProp": undefined, + "styledComponentId": "sc-AxmLO", "target": "pre", "toString": [Function], "warnTooManyClasses": [Function], @@ -1315,8 +1323,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "$$typeof": Symbol(react.forward_ref), "attrs": Array [], "componentStyle": ComponentStyle { - "baseHash": 573909505, - "componentId": "sc-fzXfLO", + "baseHash": 1280172402, + "componentId": "sc-fzozJi", "isStatic": false, "rules": Array [ " @@ -1332,7 +1340,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "displayName": "styled.code", "foldedComponentIds": Array [], "render": [Function], - "styledComponentId": "sc-fzXfLO", + "shouldForwardProp": undefined, + "styledComponentId": "sc-fzozJi", "target": "code", "toString": [Function], "warnTooManyClasses": [Function], @@ -1344,8 +1353,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "$$typeof": Symbol(react.forward_ref), "attrs": Array [], "componentStyle": ComponentStyle { - "baseHash": 3487560131, - "componentId": "sc-AykKK", + "baseHash": -1923298833, + "componentId": "sc-AxmLO", "isStatic": false, "rules": Array [ " @@ -1369,7 +1378,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`] "displayName": "styled.pre", "foldedComponentIds": Array [], "render": [Function], - "styledComponentId": "sc-AykKK", + "shouldForwardProp": undefined, + "styledComponentId": "sc-AxmLO", "target": "pre", "toString": [Function], "warnTooManyClasses": [Function], diff --git a/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts b/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts index 16546bc6070c2..2e9087b238406 100644 --- a/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts +++ b/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts @@ -3,10 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import apmIndexPattern from '../../tutorial/index_pattern.json'; -import { APM_STATIC_INDEX_PATTERN_ID } from '../../../common/index_pattern_constants'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SavedObjectsErrorHelpers } from '../../../../../../src/core/server/saved_objects'; +import { SavedObjectsErrorHelpers } from '../../../../../../src/core/server'; +import { apmIndexPattern } from '../../../../../../src/plugins/apm_oss/server'; +import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../../src/plugins/apm_oss/public'; import { hasHistoricalAgentData } from '../services/get_services/has_historical_agent_data'; import { Setup } from '../helpers/setup_request'; import { APMRequestHandlerContext } from '../../routes/typings'; diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts index f5755f998dd32..9a405030e1df0 100644 --- a/x-pack/plugins/apm/server/plugin.ts +++ b/x-pack/plugins/apm/server/plugin.ts @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { i18n } from '@kbn/i18n'; import { PluginInitializerContext, Plugin, @@ -25,7 +26,6 @@ import { createApmApi } from './routes/create_apm_api'; import { getApmIndices } from './lib/settings/apm_indices/get_apm_indices'; import { APMConfig, mergeConfigs, APMXPackConfig } from '.'; import { HomeServerPluginSetup } from '../../../../src/plugins/home/server'; -import { tutorialProvider } from './tutorial'; import { CloudSetup } from '../../cloud/server'; import { getInternalSavedObjectsClient } from './lib/helpers/get_internal_saved_objects_client'; import { LicensingPluginSetup } from '../../licensing/public'; @@ -34,6 +34,7 @@ import { createApmTelemetry } from './lib/apm_telemetry'; import { PluginSetupContract as FeaturesPluginSetup } from '../../../plugins/features/server'; import { APM_FEATURE } from './feature'; import { apmIndices, apmTelemetry } from './saved_objects'; +import { createElasticCloudInstructions } from './tutorial/elastic_cloud'; export interface APMPluginSetup { config$: Observable; @@ -96,20 +97,27 @@ export class APMPlugin implements Plugin { }); } - plugins.home.tutorials.registerTutorial( - tutorialProvider({ - isEnabled: this.currentConfig['xpack.apm.ui.enabled'], - indexPatternTitle: this.currentConfig['apm_oss.indexPattern'], - cloud: plugins.cloud, - indices: { - errorIndices: this.currentConfig['apm_oss.errorIndices'], - metricsIndices: this.currentConfig['apm_oss.metricsIndices'], - onboardingIndices: this.currentConfig['apm_oss.onboardingIndices'], - sourcemapIndices: this.currentConfig['apm_oss.sourcemapIndices'], - transactionIndices: this.currentConfig['apm_oss.transactionIndices'] - } - }) - ); + const ossTutorialProvider = plugins.apmOss.getRegisteredTutorialProvider(); + plugins.home.tutorials.unregisterTutorial(ossTutorialProvider); + plugins.home.tutorials.registerTutorial(() => { + const ossPart = ossTutorialProvider({}); + if (this.currentConfig!['xpack.apm.ui.enabled'] && ossPart.artifacts) { + ossPart.artifacts.application = { + path: '/app/apm', + label: i18n.translate( + 'xpack.apm.tutorial.specProvider.artifacts.application.label', + { + defaultMessage: 'Launch APM' + } + ) + }; + } + + return { + ...ossPart, + elasticCloud: createElasticCloudInstructions(plugins.cloud) + }; + }); plugins.features.registerFeature(APM_FEATURE); createApmApi().init(core, { diff --git a/x-pack/plugins/apm/server/tutorial/envs/elastic_cloud.ts b/x-pack/plugins/apm/server/tutorial/elastic_cloud.ts similarity index 94% rename from x-pack/plugins/apm/server/tutorial/envs/elastic_cloud.ts rename to x-pack/plugins/apm/server/tutorial/elastic_cloud.ts index 98294dddbec41..81de184ac6a9c 100644 --- a/x-pack/plugins/apm/server/tutorial/envs/elastic_cloud.ts +++ b/x-pack/plugins/apm/server/tutorial/elastic_cloud.ts @@ -5,7 +5,7 @@ */ import { i18n } from '@kbn/i18n'; -import { INSTRUCTION_VARIANT } from '../../../../../../src/plugins/home/server'; +import { INSTRUCTION_VARIANT } from '../../../../../src/plugins/home/server'; import { createNodeAgentInstructions, @@ -17,8 +17,8 @@ import { createGoAgentInstructions, createJavaAgentInstructions, createDotNetAgentInstructions -} from '../instructions/apm_agent_instructions'; -import { CloudSetup } from '../../../../cloud/server'; +} from '../../../../../src/plugins/apm_oss/server'; +import { CloudSetup } from '../../../cloud/server'; export function createElasticCloudInstructions(cloudSetup?: CloudSetup) { const apmServerUrl = cloudSetup?.apm.url; diff --git a/x-pack/plugins/apm/server/tutorial/envs/on_prem.ts b/x-pack/plugins/apm/server/tutorial/envs/on_prem.ts deleted file mode 100644 index 1f7b7c8344c1d..0000000000000 --- a/x-pack/plugins/apm/server/tutorial/envs/on_prem.ts +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -import { INSTRUCTION_VARIANT } from '../../../../../../src/plugins/home/server'; -import { - createWindowsServerInstructions, - createEditConfig, - createStartServerUnixSysv, - createStartServerUnix, - createDownloadServerRpm, - createDownloadServerDeb, - createDownloadServerOsx -} from '../instructions/apm_server_instructions'; -import { - createNodeAgentInstructions, - createDjangoAgentInstructions, - createFlaskAgentInstructions, - createRailsAgentInstructions, - createRackAgentInstructions, - createJsAgentInstructions, - createGoAgentInstructions, - createJavaAgentInstructions, - createDotNetAgentInstructions -} from '../instructions/apm_agent_instructions'; - -export function onPremInstructions({ - errorIndices, - transactionIndices, - metricsIndices, - sourcemapIndices, - onboardingIndices -}: { - errorIndices: string; - transactionIndices: string; - metricsIndices: string; - sourcemapIndices: string; - onboardingIndices: string; -}) { - const EDIT_CONFIG = createEditConfig(); - const START_SERVER_UNIX = createStartServerUnix(); - const START_SERVER_UNIX_SYSV = createStartServerUnixSysv(); - - return { - instructionSets: [ - { - title: i18n.translate('xpack.apm.tutorial.apmServer.title', { - defaultMessage: 'APM Server' - }), - callOut: { - title: i18n.translate('xpack.apm.tutorial.apmServer.callOut.title', { - defaultMessage: 'Important: Updating to 7.0 or higher' - }), - message: i18n.translate( - 'xpack.apm.tutorial.apmServer.callOut.message', - { - defaultMessage: `Please make sure your APM Server is updated to 7.0 or higher. \ - You can also migrate your 6.x data with the migration assistant found in Kibana's management section.` - } - ), - iconType: 'alert' - }, - instructionVariants: [ - { - id: INSTRUCTION_VARIANT.OSX, - instructions: [ - createDownloadServerOsx(), - EDIT_CONFIG, - START_SERVER_UNIX - ] - }, - { - id: INSTRUCTION_VARIANT.DEB, - instructions: [ - createDownloadServerDeb(), - EDIT_CONFIG, - START_SERVER_UNIX_SYSV - ] - }, - { - id: INSTRUCTION_VARIANT.RPM, - instructions: [ - createDownloadServerRpm(), - EDIT_CONFIG, - START_SERVER_UNIX_SYSV - ] - }, - { - id: INSTRUCTION_VARIANT.WINDOWS, - instructions: createWindowsServerInstructions() - } - ], - statusCheck: { - title: i18n.translate( - 'xpack.apm.tutorial.apmServer.statusCheck.title', - { - defaultMessage: 'APM Server status' - } - ), - text: i18n.translate( - 'xpack.apm.tutorial.apmServer.statusCheck.text', - { - defaultMessage: - 'Make sure APM Server is running before you start implementing the APM agents.' - } - ), - btnLabel: i18n.translate( - 'xpack.apm.tutorial.apmServer.statusCheck.btnLabel', - { - defaultMessage: 'Check APM Server status' - } - ), - success: i18n.translate( - 'xpack.apm.tutorial.apmServer.statusCheck.successMessage', - { - defaultMessage: 'You have correctly setup APM Server' - } - ), - error: i18n.translate( - 'xpack.apm.tutorial.apmServer.statusCheck.errorMessage', - { - defaultMessage: - 'No APM Server detected. Please make sure it is running and you have updated to 7.0 or higher.' - } - ), - esHitsCheck: { - index: onboardingIndices, - query: { - bool: { - filter: [ - { term: { 'processor.event': 'onboarding' } }, - { range: { 'observer.version_major': { gte: 7 } } } - ] - } - } - } - } - }, - { - title: i18n.translate('xpack.apm.tutorial.apmAgents.title', { - defaultMessage: 'APM Agents' - }), - instructionVariants: [ - { - id: INSTRUCTION_VARIANT.JAVA, - instructions: createJavaAgentInstructions() - }, - { - id: INSTRUCTION_VARIANT.JS, - instructions: createJsAgentInstructions() - }, - { - id: INSTRUCTION_VARIANT.NODE, - instructions: createNodeAgentInstructions() - }, - { - id: INSTRUCTION_VARIANT.DJANGO, - instructions: createDjangoAgentInstructions() - }, - { - id: INSTRUCTION_VARIANT.FLASK, - instructions: createFlaskAgentInstructions() - }, - { - id: INSTRUCTION_VARIANT.RAILS, - instructions: createRailsAgentInstructions() - }, - { - id: INSTRUCTION_VARIANT.RACK, - instructions: createRackAgentInstructions() - }, - { - id: INSTRUCTION_VARIANT.GO, - instructions: createGoAgentInstructions() - }, - { - id: INSTRUCTION_VARIANT.DOTNET, - instructions: createDotNetAgentInstructions() - } - ], - statusCheck: { - title: i18n.translate( - 'xpack.apm.tutorial.apmAgents.statusCheck.title', - { - defaultMessage: 'Agent status' - } - ), - text: i18n.translate( - 'xpack.apm.tutorial.apmAgents.statusCheck.text', - { - defaultMessage: - 'Make sure your application is running and the agents are sending data.' - } - ), - btnLabel: i18n.translate( - 'xpack.apm.tutorial.apmAgents.statusCheck.btnLabel', - { - defaultMessage: 'Check agent status' - } - ), - success: i18n.translate( - 'xpack.apm.tutorial.apmAgents.statusCheck.successMessage', - { - defaultMessage: - 'Data successfully received from one or more agents' - } - ), - error: i18n.translate( - 'xpack.apm.tutorial.apmAgents.statusCheck.errorMessage', - { - defaultMessage: 'No data has been received from agents yet' - } - ), - esHitsCheck: { - index: [ - errorIndices, - transactionIndices, - metricsIndices, - sourcemapIndices - ], - query: { - bool: { - filter: [ - { - terms: { - 'processor.event': [ - 'error', - 'transaction', - 'metric', - 'sourcemap' - ] - } - }, - { range: { 'observer.version_major': { gte: 7 } } } - ] - } - } - } - } - } - ] - }; -} diff --git a/x-pack/plugins/apm/server/tutorial/index.ts b/x-pack/plugins/apm/server/tutorial/index.ts deleted file mode 100644 index 76e2456afa5df..0000000000000 --- a/x-pack/plugins/apm/server/tutorial/index.ts +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -import { onPremInstructions } from './envs/on_prem'; -import { createElasticCloudInstructions } from './envs/elastic_cloud'; -import apmIndexPattern from './index_pattern.json'; -import { CloudSetup } from '../../../cloud/server'; -import { - ArtifactsSchema, - TutorialsCategory -} from '../../../../../src/plugins/home/server'; -import { APM_STATIC_INDEX_PATTERN_ID } from '../../common/index_pattern_constants'; - -const apmIntro = i18n.translate('xpack.apm.tutorial.introduction', { - defaultMessage: - 'Collect in-depth performance metrics and errors from inside your applications.' -}); - -export const tutorialProvider = ({ - isEnabled, - indexPatternTitle, - cloud, - indices -}: { - isEnabled: boolean; - indexPatternTitle: string; - cloud?: CloudSetup; - indices: { - errorIndices: string; - transactionIndices: string; - metricsIndices: string; - sourcemapIndices: string; - onboardingIndices: string; - }; -}) => () => { - const savedObjects = [ - { - ...apmIndexPattern, - id: APM_STATIC_INDEX_PATTERN_ID, - attributes: { - ...apmIndexPattern.attributes, - title: indexPatternTitle - } - } - ]; - - const artifacts: ArtifactsSchema = { - dashboards: [ - { - id: '8d3ed660-7828-11e7-8c47-65b845b5cfb3', - linkLabel: i18n.translate( - 'xpack.apm.tutorial.specProvider.artifacts.dashboards.linkLabel', - { - defaultMessage: 'APM dashboard' - } - ), - isOverview: true - } - ] - }; - - if (isEnabled) { - artifacts.application = { - path: '/app/apm', - label: i18n.translate( - 'xpack.apm.tutorial.specProvider.artifacts.application.label', - { - defaultMessage: 'Launch APM' - } - ) - }; - } - - return { - id: 'apm', - name: i18n.translate('xpack.apm.tutorial.specProvider.name', { - defaultMessage: 'APM' - }), - category: TutorialsCategory.OTHER, - shortDescription: apmIntro, - longDescription: i18n.translate( - 'xpack.apm.tutorial.specProvider.longDescription', - { - defaultMessage: - 'Application Performance Monitoring (APM) collects in-depth \ -performance metrics and errors from inside your application. \ -It allows you to monitor the performance of thousands of applications in real time. \ -[Learn more]({learnMoreLink}).', - values: { - learnMoreLink: - '{config.docs.base_url}guide/en/apm/get-started/{config.docs.version}/index.html' - } - } - ), - euiIconType: 'apmApp', - artifacts, - onPrem: onPremInstructions(indices), - elasticCloud: createElasticCloudInstructions(cloud), - previewImagePath: '/plugins/apm/assets/apm.png', - savedObjects, - savedObjectsInstallMsg: i18n.translate( - 'xpack.apm.tutorial.specProvider.savedObjectsInstallMsg', - { - defaultMessage: - 'An APM index pattern is required for some features in the APM UI.' - } - ) - }; -}; diff --git a/x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts b/x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts deleted file mode 100644 index 799c12517b7c0..0000000000000 --- a/x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts +++ /dev/null @@ -1,805 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; - -export const createNodeAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.nodeClient.install.title', { - defaultMessage: 'Install the APM agent' - }), - textPre: i18n.translate('xpack.apm.tutorial.nodeClient.install.textPre', { - defaultMessage: - 'Install the APM agent for Node.js as a dependency to your application.' - }), - commands: ['npm install elastic-apm-node --save'] - }, - { - title: i18n.translate('xpack.apm.tutorial.nodeClient.configure.title', { - defaultMessage: 'Configure the agent' - }), - textPre: i18n.translate('xpack.apm.tutorial.nodeClient.configure.textPre', { - defaultMessage: - 'Agents are libraries that run inside of your application process. \ -APM services are created programmatically based on the `serviceName`. \ -This agent supports a vararity of frameworks but can also be used with your custom stack.' - }), - commands: `// ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.addThisToTheFileTopComment', - { - defaultMessage: - 'Add this to the VERY top of the first file loaded in your app' - } - )} -var apm = require('elastic-apm-node').start({curlyOpen} - // ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.setRequiredServiceNameComment', - { - defaultMessage: 'Override service name from package.json' - } - )} - // ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.allowedCharactersComment', - { - defaultMessage: 'Allowed characters: a-z, A-Z, 0-9, -, _, and space' - } - )} - serviceName: '', - - // ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.useIfApmRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a token' - } - )} - secretToken: '${secretToken}', - - // ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.setCustomApmServerUrlComment', - { - defaultMessage: - 'Set custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' } - } - )} - serverUrl: '${apmServerUrl}' -{curlyClose})`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.textPost', - { - defaultMessage: - 'See [the documentation]({documentationLink}) for advanced usage, including how to use with \ -[Babel/ES Modules]({babelEsModulesLink}).', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/nodejs/current/index.html', - babelEsModulesLink: - '{config.docs.base_url}guide/en/apm/agent/nodejs/current/advanced-setup.html#es-modules' - } - } - ) - } -]; - -export const createDjangoAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.djangoClient.install.title', { - defaultMessage: 'Install the APM agent' - }), - textPre: i18n.translate('xpack.apm.tutorial.djangoClient.install.textPre', { - defaultMessage: 'Install the APM agent for Python as a dependency.' - }), - commands: ['$ pip install elastic-apm'] - }, - { - title: i18n.translate('xpack.apm.tutorial.djangoClient.configure.title', { - defaultMessage: 'Configure the agent' - }), - textPre: i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.textPre', - { - defaultMessage: - 'Agents are libraries that run inside of your application process. \ -APM services are created programmatically based on the `SERVICE_NAME`.' - } - ), - commands: `# ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.addAgentComment', - { - defaultMessage: 'Add the agent to the installed apps' - } - )} -INSTALLED_APPS = ( - 'elasticapm.contrib.django', - # ... -) - -ELASTIC_APM = {curlyOpen} - # ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.setRequiredServiceNameComment', - { - defaultMessage: 'Set required service name. Allowed characters:' - } - )} - # ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.allowedCharactersComment', - { - defaultMessage: 'a-z, A-Z, 0-9, -, _, and space' - } - )} - 'SERVICE_NAME': '', - - # ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.useIfApmServerRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a token' - } - )} - 'SECRET_TOKEN': '${secretToken}', - - # ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment', - { - defaultMessage: - 'Set custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' } - } - )} - 'SERVER_URL': '${apmServerUrl}', -{curlyClose} - -# ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.addTracingMiddlewareComment', - { - defaultMessage: - 'To send performance metrics, add our tracing middleware:' - } - )} -MIDDLEWARE = ( - 'elasticapm.contrib.django.middleware.TracingMiddleware', - #... -)`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.textPost', - { - defaultMessage: - 'See the [documentation]({documentationLink}) for advanced usage.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/python/current/django-support.html' - } - } - ) - } -]; - -export const createFlaskAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.flaskClient.install.title', { - defaultMessage: 'Install the APM agent' - }), - textPre: i18n.translate('xpack.apm.tutorial.flaskClient.install.textPre', { - defaultMessage: 'Install the APM agent for Python as a dependency.' - }), - commands: ['$ pip install elastic-apm[flask]'] - }, - { - title: i18n.translate('xpack.apm.tutorial.flaskClient.configure.title', { - defaultMessage: 'Configure the agent' - }), - textPre: i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.textPre', - { - defaultMessage: - 'Agents are libraries that run inside of your application process. \ -APM services are created programmatically based on the `SERVICE_NAME`.' - } - ), - commands: `# ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.initializeUsingEnvironmentVariablesComment', - { - defaultMessage: 'initialize using environment variables' - } - )} -from elasticapm.contrib.flask import ElasticAPM -app = Flask(__name__) -apm = ElasticAPM(app) - -# ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.configureElasticApmComment', - { - defaultMessage: - "or configure to use ELASTIC_APM in your application's settings" - } - )} -from elasticapm.contrib.flask import ElasticAPM -app.config['ELASTIC_APM'] = {curlyOpen} - # ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.setRequiredServiceNameComment', - { - defaultMessage: 'Set required service name. Allowed characters:' - } - )} - # ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.allowedCharactersComment', - { - defaultMessage: 'a-z, A-Z, 0-9, -, _, and space' - } - )} - 'SERVICE_NAME': '', - - # ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.useIfApmServerRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a token' - } - )} - 'SECRET_TOKEN': '${secretToken}', - - # ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.setCustomApmServerUrlComment', - { - defaultMessage: - 'Set custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' } - } - )} - 'SERVER_URL': '${apmServerUrl}', -{curlyClose} - -apm = ElasticAPM(app)`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.textPost', - { - defaultMessage: - 'See the [documentation]({documentationLink}) for advanced usage.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/python/current/flask-support.html' - } - } - ) - } -]; - -export const createRailsAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.railsClient.install.title', { - defaultMessage: 'Install the APM agent' - }), - textPre: i18n.translate('xpack.apm.tutorial.railsClient.install.textPre', { - defaultMessage: 'Add the agent to your Gemfile.' - }), - commands: [`gem 'elastic-apm'`] - }, - { - title: i18n.translate('xpack.apm.tutorial.railsClient.configure.title', { - defaultMessage: 'Configure the agent' - }), - textPre: i18n.translate( - 'xpack.apm.tutorial.railsClient.configure.textPre', - { - defaultMessage: - 'APM is automatically started when your app boots. Configure the agent, by creating the config file {configFile}', - values: { configFile: '`config/elastic_apm.yml`' } - } - ), - commands: `# config/elastic_apm.yml: - -# Set service name - allowed characters: a-z, A-Z, 0-9, -, _ and space -# Defaults to the name of your Rails app -# service_name: 'my-service' - -# Use if APM Server requires a token -# secret_token: '${secretToken}' - -# Set custom APM Server URL (default: http://localhost:8200) -# server_url: '${apmServerUrl || 'http://localhost:8200'}'`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.railsClient.configure.textPost', - { - defaultMessage: - 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html' - } - } - ) - } -]; - -export const createRackAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.rackClient.install.title', { - defaultMessage: 'Install the APM agent' - }), - textPre: i18n.translate('xpack.apm.tutorial.rackClient.install.textPre', { - defaultMessage: 'Add the agent to your Gemfile.' - }), - commands: [`gem 'elastic-apm'`] - }, - { - title: i18n.translate('xpack.apm.tutorial.rackClient.configure.title', { - defaultMessage: 'Configure the agent' - }), - textPre: i18n.translate('xpack.apm.tutorial.rackClient.configure.textPre', { - defaultMessage: - 'For Rack or a compatible framework (e.g. Sinatra), include the middleware in your app and start the agent.' - }), - commands: `# config.ru - require 'sinatra/base' - - class MySinatraApp < Sinatra::Base - use ElasticAPM::Middleware - - # ... - end - - ElasticAPM.start( - app: MySinatraApp, # ${i18n.translate( - 'xpack.apm.tutorial.rackClient.configure.commands.requiredComment', - { - defaultMessage: 'required' - } - )} - config_file: '' # ${i18n.translate( - 'xpack.apm.tutorial.rackClient.configure.commands.optionalComment', - { - defaultMessage: 'optional, defaults to config/elastic_apm.yml' - } - )} - ) - - run MySinatraApp - - at_exit {curlyOpen} ElasticAPM.stop {curlyClose}`.split('\n') - }, - { - title: i18n.translate('xpack.apm.tutorial.rackClient.createConfig.title', { - defaultMessage: 'Create config file' - }), - textPre: i18n.translate( - 'xpack.apm.tutorial.rackClient.createConfig.textPre', - { - defaultMessage: 'Create a config file {configFile}:', - values: { configFile: '`config/elastic_apm.yml`' } - } - ), - commands: `# config/elastic_apm.yml: - -# ${i18n.translate( - 'xpack.apm.tutorial.rackClient.createConfig.commands.setServiceNameComment', - { - defaultMessage: - 'Set service name - allowed characters: a-z, A-Z, 0-9, -, _ and space' - } - )} -# ${i18n.translate( - 'xpack.apm.tutorial.rackClient.createConfig.commands.defaultsToTheNameOfRackAppClassComment', - { - defaultMessage: "Defaults to the name of your Rack app's class." - } - )} -# service_name: 'my-service' - -# ${i18n.translate( - 'xpack.apm.tutorial.rackClient.createConfig.commands.useIfApmServerRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a token' - } - )} -# secret_token: '${secretToken}' - -# ${i18n.translate( - 'xpack.apm.tutorial.rackClient.createConfig.commands.setCustomApmServerComment', - { - defaultMessage: - 'Set custom APM Server URL (default: {defaultServerUrl})', - values: { defaultServerUrl: 'http://localhost:8200' } - } - )} -# server_url: '${apmServerUrl || 'http://localhost:8200'}'`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.rackClient.createConfig.textPost', - { - defaultMessage: - 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html' - } - } - ) - } -]; - -export const createJsAgentInstructions = (apmServerUrl = '') => [ - { - title: i18n.translate( - 'xpack.apm.tutorial.jsClient.enableRealUserMonitoring.title', - { - defaultMessage: 'Enable Real User Monitoring support in APM Server' - } - ), - textPre: i18n.translate( - 'xpack.apm.tutorial.jsClient.enableRealUserMonitoring.textPre', - { - defaultMessage: - 'APM Server disables RUM support by default. See the [documentation]({documentationLink}) \ -for details on how to enable RUM support.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/server/{config.docs.version}/configuration-rum.html' - } - } - ) - }, - { - title: i18n.translate( - 'xpack.apm.tutorial.jsClient.installDependency.title', - { - defaultMessage: 'Set up the Agent as a dependency' - } - ), - textPre: i18n.translate( - 'xpack.apm.tutorial.jsClient.installDependency.textPre', - { - defaultMessage: - 'You can install the Agent as a dependency to your application with \ -`npm install @elastic/apm-rum --save`.\n\n\ -The Agent can then be initialized and configured in your application like this:' - } - ), - commands: `import {curlyOpen} init as initApm {curlyClose} from '@elastic/apm-rum' -var apm = initApm({curlyOpen} - - // ${i18n.translate( - 'xpack.apm.tutorial.jsClient.installDependency.commands.setRequiredServiceNameComment', - { - defaultMessage: - 'Set required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)' - } - )} - serviceName: 'your-app-name', - - // ${i18n.translate( - 'xpack.apm.tutorial.jsClient.installDependency.commands.setCustomApmServerUrlComment', - { - defaultMessage: - 'Set custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' } - } - )} - serverUrl: '${apmServerUrl}', - - // ${i18n.translate( - 'xpack.apm.tutorial.jsClient.installDependency.commands.setServiceVersionComment', - { - defaultMessage: 'Set service version (required for source map feature)' - } - )} - serviceVersion: '' -{curlyClose})`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.jsClient.installDependency.textPost', - { - defaultMessage: - 'Framework integrations, like React or Angular, have custom dependencies. \ -See the [integration documentation]({docLink}) for more information.', - values: { - docLink: - '{config.docs.base_url}guide/en/apm/agent/rum-js/current/framework-integrations.html' - } - } - ) - }, - { - title: i18n.translate('xpack.apm.tutorial.jsClient.scriptTags.title', { - defaultMessage: 'Set up the Agent with Script Tags' - }), - textPre: i18n.translate('xpack.apm.tutorial.jsClient.scriptTags.textPre', { - defaultMessage: - "Alternatively, you can use Script tags to set up and configure the Agent. \ -Add a ` - -`.split('\n') - } -]; - -export const createGoAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.goClient.install.title', { - defaultMessage: 'Install the APM agent' - }), - textPre: i18n.translate('xpack.apm.tutorial.goClient.install.textPre', { - defaultMessage: 'Install the APM agent packages for Go.' - }), - commands: ['go get go.elastic.co/apm'] - }, - { - title: i18n.translate('xpack.apm.tutorial.goClient.configure.title', { - defaultMessage: 'Configure the agent' - }), - textPre: i18n.translate('xpack.apm.tutorial.goClient.configure.textPre', { - defaultMessage: - 'Agents are libraries that run inside of your application process. \ -APM services are created programmatically based on the executable \ -file name, or the `ELASTIC_APM_SERVICE_NAME` environment variable.' - }), - commands: `# ${i18n.translate( - 'xpack.apm.tutorial.goClient.configure.commands.initializeUsingEnvironmentVariablesComment', - { - defaultMessage: 'Initialize using environment variables:' - } - )} - -# ${i18n.translate( - 'xpack.apm.tutorial.goClient.configure.commands.setServiceNameComment', - { - defaultMessage: - 'Set the service name. Allowed characters: # a-z, A-Z, 0-9, -, _, and space.' - } - )} -# ${i18n.translate( - 'xpack.apm.tutorial.goClient.configure.commands.usedExecutableNameComment', - { - defaultMessage: - 'If ELASTIC_APM_SERVICE_NAME is not specified, the executable name will be used.' - } - )} -export ELASTIC_APM_SERVICE_NAME= - -# ${i18n.translate( - 'xpack.apm.tutorial.goClient.configure.commands.setCustomApmServerUrlComment', - { - defaultMessage: - 'Set custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' } - } - )} -export ELASTIC_APM_SERVER_URL=${apmServerUrl} - -# ${i18n.translate( - 'xpack.apm.tutorial.goClient.configure.commands.useIfApmRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a token' - } - )} -export ELASTIC_APM_SECRET_TOKEN=${secretToken} -`.split('\n'), - textPost: i18n.translate('xpack.apm.tutorial.goClient.configure.textPost', { - defaultMessage: - 'See the [documentation]({documentationLink}) for advanced configuration.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/go/current/configuration.html' - } - }) - }, - { - title: i18n.translate('xpack.apm.tutorial.goClient.instrument.title', { - defaultMessage: 'Instrument your application' - }), - textPre: i18n.translate('xpack.apm.tutorial.goClient.instrument.textPre', { - defaultMessage: - 'Instrument your Go application by using one of the provided instrumentation modules or \ -by using the tracer API directly.' - }), - commands: `\ -import ( - "net/http" - - "go.elastic.co/apm/module/apmhttp" -) - -func main() {curlyOpen} - mux := http.NewServeMux() - ... - http.ListenAndServe(":8080", apmhttp.Wrap(mux)) -{curlyClose} -`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.goClient.instrument.textPost', - { - defaultMessage: - 'See the [documentation]({documentationLink}) for a detailed \ -guide to instrumenting Go source code.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/go/current/instrumenting-source.html' - } - } - ) - } -]; - -export const createJavaAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.javaClient.download.title', { - defaultMessage: 'Download the APM agent' - }), - textPre: i18n.translate('xpack.apm.tutorial.javaClient.download.textPre', { - defaultMessage: - 'Download the agent jar from [Maven Central]({mavenCentralLink}). \ -Do **not** add the agent as a dependency to your application.', - values: { - mavenCentralLink: - 'http://search.maven.org/#search%7Cga%7C1%7Ca%3Aelastic-apm-agent' - } - }) - }, - { - title: i18n.translate( - 'xpack.apm.tutorial.javaClient.startApplication.title', - { - defaultMessage: 'Start your application with the javaagent flag' - } - ), - textPre: i18n.translate( - 'xpack.apm.tutorial.javaClient.startApplication.textPre', - { - defaultMessage: - 'Add the `-javaagent` flag and configure the agent with system properties.\n\n \ -* Set required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)\n \ -* Set custom APM Server URL (default: {customApmServerUrl})\n \ -* Set the base package of your application', - values: { customApmServerUrl: 'http://localhost:8200' } - } - ), - commands: `java -javaagent:/path/to/elastic-apm-agent-.jar \\ - -Delastic.apm.service_name=my-application \\ - -Delastic.apm.server_urls=${apmServerUrl || 'http://localhost:8200'} \\ - -Delastic.apm.secret_token=${secretToken} \\ - -Delastic.apm.application_packages=org.example \\ - -jar my-application.jar`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.javaClient.startApplication.textPost', - { - defaultMessage: - 'See the [documentation]({documentationLink}) for configuration options and advanced \ -usage.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/java/current/index.html' - } - } - ) - } -]; - -export const createDotNetAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.dotNetClient.download.title', { - defaultMessage: 'Download the APM agent' - }), - textPre: i18n.translate( - 'xpack.apm.tutorial.dotNetClient.download.textPre', - { - defaultMessage: - 'Add the the agent package(s) from [NuGet]({allNuGetPackagesLink}) to your .NET application. There are multiple \ - NuGet packages available for different use cases. \n\nFor an ASP.NET Core application with Entity Framework \ - Core download the [Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink}) package. This package will automatically add every \ - agent component to your application. \n\n In case you would like to to minimize the dependencies, you can use the \ - [Elastic.Apm.AspNetCore]({aspNetCorePackageLink}) package for just \ - ASP.NET Core monitoring or the [Elastic.Apm.EfCore]({efCorePackageLink}) package for just Entity Framework Core monitoring. \n\n \ - In case you only want to use the public Agent API for manual instrumentation use the [Elastic.Apm]({elasticApmPackageLink}) package.', - values: { - allNuGetPackagesLink: 'https://www.nuget.org/packages?q=Elastic.apm', - netCoreAllApmPackageLink: - 'https://www.nuget.org/packages/Elastic.Apm.NetCoreAll', - aspNetCorePackageLink: - 'https://www.nuget.org/packages/Elastic.Apm.AspNetCore', - efCorePackageLink: - 'https://www.nuget.org/packages/Elastic.Apm.EntityFrameworkCore', - elasticApmPackageLink: 'https://www.nuget.org/packages/Elastic.Apm' - } - } - ) - }, - { - title: i18n.translate( - 'xpack.apm.tutorial.dotNetClient.configureApplication.title', - { - defaultMessage: 'Add the agent to the application' - } - ), - textPre: i18n.translate( - 'xpack.apm.tutorial.dotNetClient.configureApplication.textPre', - { - defaultMessage: - 'In case of ASP.NET Core with the `Elastic.Apm.NetCoreAll` package, call the `UseAllElasticApm` \ - method in the `Configure` method within the `Startup.cs` file.' - } - ), - commands: `public class Startup -{curlyOpen} - public void Configure(IApplicationBuilder app, IHostingEnvironment env) - {curlyOpen} - app.UseAllElasticApm(Configuration); - //…rest of the method - {curlyClose} - //…rest of the class -{curlyClose}`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.dotNetClient.configureApplication.textPost', - { - defaultMessage: - 'Passing an `IConfiguration` instance is optional and by doing so, the agent will read config settings through this \ - `IConfiguration` instance (e.g. from the `appsettings.json` file).' - } - ) - }, - { - title: i18n.translate( - 'xpack.apm.tutorial.dotNetClient.configureAgent.title', - { - defaultMessage: 'Sample appsettings.json file:' - } - ), - commands: `{curlyOpen} - "ElasticApm": {curlyOpen} - "SecretToken": "${secretToken}", - "ServerUrls": "${apmServerUrl || - 'http://localhost:8200'}", //Set custom APM Server URL (default: http://localhost:8200) - "ServiceName" : "MyApp", //allowed characters: a-z, A-Z, 0-9, -, _, and space. Default is the entry assembly of the application - {curlyClose} -{curlyClose}`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.dotNetClient.configureAgent.textPost', - { - defaultMessage: - 'In case you don’t pass an `IConfiguration` instance to the agent (e.g. in case of non ASP.NET Core applications) \ - you can also configure the agent through environment variables. \n \ - See [the documentation]({documentationLink}) for advanced usage.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/dotnet/current/configuration.html' - } - } - ) - } -]; diff --git a/x-pack/plugins/apm/server/tutorial/instructions/apm_server_instructions.ts b/x-pack/plugins/apm/server/tutorial/instructions/apm_server_instructions.ts deleted file mode 100644 index 371c3928802ae..0000000000000 --- a/x-pack/plugins/apm/server/tutorial/instructions/apm_server_instructions.ts +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; - -export const createEditConfig = () => ({ - title: i18n.translate('xpack.apm.tutorial.editConfig.title', { - defaultMessage: 'Edit the configuration' - }), - textPre: i18n.translate('xpack.apm.tutorial.editConfig.textPre', { - defaultMessage: - "If you're using an X-Pack secured version of Elastic Stack, you must specify \ -credentials in the `apm-server.yml` config file." - }), - commands: [ - 'output.elasticsearch:', - ' hosts: [""]', - ' username: ', - ' password: ' - ] -}); - -const createStartServer = () => ({ - title: i18n.translate('xpack.apm.tutorial.startServer.title', { - defaultMessage: 'Start APM Server' - }), - textPre: i18n.translate('xpack.apm.tutorial.startServer.textPre', { - defaultMessage: - 'The server processes and stores application performance metrics in Elasticsearch.' - }) -}); - -export function createStartServerUnixSysv() { - const START_SERVER = createStartServer(); - - return { - title: START_SERVER.title, - textPre: START_SERVER.textPre, - commands: ['service apm-server start'] - }; -} - -export function createStartServerUnix() { - const START_SERVER = createStartServer(); - - return { - title: START_SERVER.title, - textPre: START_SERVER.textPre, - commands: ['./apm-server -e'] - }; -} - -const createDownloadServerTitle = () => - i18n.translate('xpack.apm.tutorial.downloadServer.title', { - defaultMessage: 'Download and unpack APM Server' - }); - -export const createDownloadServerOsx = () => ({ - title: createDownloadServerTitle(), - commands: [ - 'curl -L -O https://artifacts.elastic.co/downloads/apm-server/apm-server-{config.kibana.version}-darwin-x86_64.tar.gz', - 'tar xzvf apm-server-{config.kibana.version}-darwin-x86_64.tar.gz', - 'cd apm-server-{config.kibana.version}-darwin-x86_64/' - ] -}); - -export const createDownloadServerDeb = () => ({ - title: createDownloadServerTitle(), - commands: [ - 'curl -L -O https://artifacts.elastic.co/downloads/apm-server/apm-server-{config.kibana.version}-amd64.deb', - 'sudo dpkg -i apm-server-{config.kibana.version}-amd64.deb' - ], - textPost: i18n.translate('xpack.apm.tutorial.downloadServerTitle', { - defaultMessage: - 'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).', - values: { - downloadPageLink: '{config.docs.base_url}downloads/apm/apm-server' - } - }) -}); - -export const createDownloadServerRpm = () => ({ - title: createDownloadServerTitle(), - commands: [ - 'curl -L -O https://artifacts.elastic.co/downloads/apm-server/apm-server-{config.kibana.version}-x86_64.rpm', - 'sudo rpm -vi apm-server-{config.kibana.version}-x86_64.rpm' - ], - textPost: i18n.translate('xpack.apm.tutorial.downloadServerRpm', { - defaultMessage: - 'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).', - values: { - downloadPageLink: '{config.docs.base_url}downloads/apm/apm-server' - } - }) -}); - -export function createWindowsServerInstructions() { - const START_SERVER = createStartServer(); - - return [ - { - title: createDownloadServerTitle(), - textPre: i18n.translate( - 'xpack.apm.tutorial.windowsServerInstructions.textPre', - { - defaultMessage: - '1. Download the APM Server Windows zip file from the \ -[Download page]({downloadPageLink}).\n2. Extract the contents of \ -the zip file into {zipFileExtractFolder}.\n3. Rename the {apmServerDirectory} \ -directory to `APM-Server`.\n4. Open a PowerShell prompt as an Administrator \ -(right-click the PowerShell icon and select \ -**Run As Administrator**). If you are running Windows XP, you might need to download and install \ -PowerShell.\n5. From the PowerShell prompt, run the following commands to install APM Server as a Windows service:', - values: { - downloadPageLink: 'https://www.elastic.co/downloads/apm/apm-server', - zipFileExtractFolder: '`C:\\Program Files`', - apmServerDirectory: '`apm-server-{config.kibana.version}-windows`' - } - } - ), - commands: [ - `cd 'C:\\Program Files\\APM-Server'`, - `.\\install-service-apm-server.ps1` - ], - textPost: i18n.translate( - 'xpack.apm.tutorial.windowsServerInstructions.textPost', - { - defaultMessage: - 'Note: If script execution is disabled on your system, \ -you need to set the execution policy for the current session \ -to allow the script to run. For example: {command}.', - values: { - command: - '`PowerShell.exe -ExecutionPolicy UnRestricted -File .\\install-service-apm-server.ps1`' - } - } - ) - }, - createEditConfig(), - { - title: START_SERVER.title, - textPre: START_SERVER.textPre, - commands: ['Start-Service apm-server'] - } - ]; -} diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/text_datatype.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/text_datatype.test.tsx index 46735f0e741e9..e708bf1b4de66 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/text_datatype.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/datatypes/text_datatype.test.tsx @@ -24,7 +24,8 @@ export const defaultTextParameters = { store: false, }; -describe('Mappings editor: text datatype', () => { +// FLAKY: https://github.com/elastic/kibana/issues/66669 +describe.skip('Mappings editor: text datatype', () => { let testBed: MappingsEditorTestBed; /** diff --git a/x-pack/plugins/infra/server/routes/log_entries/summary.ts b/x-pack/plugins/infra/server/routes/log_entries/summary.ts index aa4421374ec12..c1d532fa5a083 100644 --- a/x-pack/plugins/infra/server/routes/log_entries/summary.ts +++ b/x-pack/plugins/infra/server/routes/log_entries/summary.ts @@ -20,6 +20,7 @@ import { logEntriesSummaryResponseRT, } from '../../../common/http_api/log_entries'; import { parseFilterQuery } from '../../utils/serialized_query'; +import { UsageCollector } from '../../usage/usage_collector'; const escapeHatch = schema.object({}, { unknowns: 'allow' }); @@ -47,6 +48,8 @@ export const initLogEntriesSummaryRoute = ({ framework, logEntries }: InfraBacke parseFilterQuery(query) ); + UsageCollector.countLogs(); + return response.ok({ body: logEntriesSummaryResponseRT.encode({ data: { diff --git a/x-pack/plugins/ingest_manager/README.md b/x-pack/plugins/ingest_manager/README.md index 0e7abcc3d74a9..9641c56097422 100644 --- a/x-pack/plugins/ingest_manager/README.md +++ b/x-pack/plugins/ingest_manager/README.md @@ -28,7 +28,7 @@ One common development workflow is: ``` - Start Kibana in another shell ``` - yarn start --xpack.ingestManager.enabled=true --no-base-path --xpack.endpoint.enabled=true + yarn start --xpack.ingestManager.enabled=true --no-base-path ``` This plugin follows the `common`, `server`, `public` structure from the [Architecture Style Guide diff --git a/x-pack/plugins/ingest_manager/package.json b/x-pack/plugins/ingest_manager/package.json index 56b7df6b56852..052d3d0b42c7e 100644 --- a/x-pack/plugins/ingest_manager/package.json +++ b/x-pack/plugins/ingest_manager/package.json @@ -1,11 +1,7 @@ { - "author": "Elastic", - "name": "ingest-manager", - "version": "8.0.0", - "private": true, - "license": "Elastic-License", - "dependencies": { - "react-markdown": "^4.2.2" - } - } - \ No newline at end of file + "author": "Elastic", + "name": "ingest-manager", + "version": "8.0.0", + "private": true, + "license": "Elastic-License" +} diff --git a/x-pack/plugins/ingest_manager/yarn.lock b/x-pack/plugins/ingest_manager/yarn.lock deleted file mode 120000 index 6e09764ec763b..0000000000000 --- a/x-pack/plugins/ingest_manager/yarn.lock +++ /dev/null @@ -1 +0,0 @@ -../../../yarn.lock \ No newline at end of file diff --git a/x-pack/plugins/security/public/authentication/access_agreement/__snapshots__/access_agreement_page.test.tsx.snap b/x-pack/plugins/security/public/authentication/access_agreement/__snapshots__/access_agreement_page.test.tsx.snap index 2227cbe8a495c..04dd39c69e64d 100644 --- a/x-pack/plugins/security/public/authentication/access_agreement/__snapshots__/access_agreement_page.test.tsx.snap +++ b/x-pack/plugins/security/public/authentication/access_agreement/__snapshots__/access_agreement_page.test.tsx.snap @@ -4,6 +4,7 @@ exports[`AccessAgreementPage renders as expected when state is available 1`] = ` -

- This is + + This is + - link + + link +

-
+
`; diff --git a/x-pack/plugins/security/public/authentication/login/components/login_form/__snapshots__/login_form.test.tsx.snap b/x-pack/plugins/security/public/authentication/login/components/login_form/__snapshots__/login_form.test.tsx.snap index 072a025aa06a0..08f8034538ac3 100644 --- a/x-pack/plugins/security/public/authentication/login/components/login_form/__snapshots__/login_form.test.tsx.snap +++ b/x-pack/plugins/security/public/authentication/login/components/login_form/__snapshots__/login_form.test.tsx.snap @@ -4,6 +4,7 @@ exports[`LoginForm login selector properly switches to login form -> login help login help sourcePos={false} transformLinkUri={[Function]} > -

- some help + + some help +

-
+
`; @@ -31,6 +38,7 @@ exports[`LoginForm login selector properly switches to login help: Login Help 1` -

- some help + + some help +

-
+
`; @@ -58,6 +72,7 @@ exports[`LoginForm properly switches to login help: Login Help 1`] = ` -

- some help + + some help +

-
+
`; diff --git a/x-pack/plugins/siem/package.json b/x-pack/plugins/siem/package.json index 6dc3aa3a5021e..f61ab8e946b15 100644 --- a/x-pack/plugins/siem/package.json +++ b/x-pack/plugins/siem/package.json @@ -18,7 +18,6 @@ "dependencies": { "lodash": "^4.17.15", "querystring": "^0.2.0", - "react-markdown": "^4.0.6", "redux-devtools-extension": "^2.13.8", "@types/seedrandom": ">=2.0.0 <4.0.0" } diff --git a/x-pack/plugins/siem/public/common/components/link_icon/index.test.tsx b/x-pack/plugins/siem/public/common/components/link_icon/index.test.tsx index 859348d2b923f..557c884295529 100644 --- a/x-pack/plugins/siem/public/common/components/link_icon/index.test.tsx +++ b/x-pack/plugins/siem/public/common/components/link_icon/index.test.tsx @@ -79,7 +79,7 @@ describe('LinkIcon', () => { ); - expect(wrapper.find('.siemLinkIcon').first()).toHaveStyleRule('flex-direction', 'row-reverse'); + expect(wrapper.find('.siemLinkIcon').at(1)).toHaveStyleRule('flex-direction', 'row-reverse'); }); test('it positions the icon to the left when iconSide is left (or not provided)', () => { @@ -91,7 +91,7 @@ describe('LinkIcon', () => { ); - expect(wrapper.find('.siemLinkIcon').first()).not.toHaveStyleRule( + expect(wrapper.find('.siemLinkIcon').at(1)).not.toHaveStyleRule( 'flex-direction', 'row-reverse' ); diff --git a/x-pack/plugins/siem/public/common/components/markdown/__snapshots__/index.test.tsx.snap b/x-pack/plugins/siem/public/common/components/markdown/__snapshots__/index.test.tsx.snap index ce0c797c2b2b4..4850547f30c52 100644 --- a/x-pack/plugins/siem/public/common/components/markdown/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/siem/public/common/components/markdown/__snapshots__/index.test.tsx.snap @@ -6,6 +6,7 @@ exports[`Markdown markdown links it renders the expected content containing a li data-test-subj="markdown" escapeHtml={true} linkTarget="_blank" + parserOptions={Object {}} plugins={Array []} rawSourcePos={false} renderers={ @@ -32,6 +33,7 @@ exports[`Markdown markdown tables it renders the expected table content 1`] = ` data-test-subj="markdown" escapeHtml={true} linkTarget="_blank" + parserOptions={Object {}} plugins={Array []} rawSourcePos={false} renderers={ diff --git a/x-pack/plugins/siem/public/common/components/matrix_histogram/__snapshots__/index.test.tsx.snap b/x-pack/plugins/siem/public/common/components/matrix_histogram/__snapshots__/index.test.tsx.snap index c4bdff7ea649a..c0e0988168384 100644 --- a/x-pack/plugins/siem/public/common/components/matrix_histogram/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/siem/public/common/components/matrix_histogram/__snapshots__/index.test.tsx.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Matrix Histogram Component not initial load it renders no MatrixLoader 1`] = `"
"`; +exports[`Matrix Histogram Component not initial load it renders no MatrixLoader 1`] = `"
"`; -exports[`Matrix Histogram Component on initial load it renders MatrixLoader 1`] = `"
"`; +exports[`Matrix Histogram Component on initial load it renders MatrixLoader 1`] = `"
"`; diff --git a/x-pack/plugins/siem/public/common/components/stat_items/__snapshots__/index.test.tsx.snap b/x-pack/plugins/siem/public/common/components/stat_items/__snapshots__/index.test.tsx.snap index e15ce0ae5f543..0d006d18cc49b 100644 --- a/x-pack/plugins/siem/public/common/components/stat_items/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/siem/public/common/components/stat_items/__snapshots__/index.test.tsx.snap @@ -38,18 +38,18 @@ exports[`Stat Items Component disable charts it renders the default widget 1`] = data-test-subj="stat-item" >

@@ -258,18 +258,18 @@ exports[`Stat Items Component disable charts it renders the default widget 2`] = data-test-subj="stat-item" >

@@ -548,18 +548,18 @@ exports[`Stat Items Component rendering kpis with charts it renders the default data-test-subj="stat-item" >

1,714 @@ -734,10 +734,10 @@ exports[`Stat Items Component rendering kpis with charts it renders the default key="stat-items-field-uniqueDestinationIps" >

2,359 @@ -815,10 +815,10 @@ exports[`Stat Items Component rendering kpis with charts it renders the default >

{ ); expect( - wrapper.find(`.field-browser-category-pane-${selectedCategoryId}-${timelineId}`).first() + wrapper.find(`.field-browser-category-pane-${selectedCategoryId}-${timelineId}`).at(1) ).toHaveStyleRule('font-weight', 'bold', { modifier: '.euiText' }); }); @@ -109,7 +109,7 @@ describe('getCategoryColumns', () => { ); expect( - wrapper.find(`.field-browser-category-pane-${notTheSelectedCategoryId}-${timelineId}`).first() + wrapper.find(`.field-browser-category-pane-${notTheSelectedCategoryId}-${timelineId}`).at(1) ).toHaveStyleRule('font-weight', 'normal', { modifier: '.euiText' }); }); diff --git a/x-pack/plugins/siem/public/timelines/components/fields_browser/index.test.tsx b/x-pack/plugins/siem/public/timelines/components/fields_browser/index.test.tsx index 798fa53e607ed..ef37ed0a67d9e 100644 --- a/x-pack/plugins/siem/public/timelines/components/fields_browser/index.test.tsx +++ b/x-pack/plugins/siem/public/timelines/components/fields_browser/index.test.tsx @@ -148,7 +148,7 @@ describe('StatefulFieldsBrowser', () => { wrapper.update(); expect( - wrapper.find(`.field-browser-category-pane-auditd-${timelineId}`).first() + wrapper.find(`.field-browser-category-pane-auditd-${timelineId}`).at(1) ).toHaveStyleRule('font-weight', 'bold', { modifier: '.euiText' }); }); @@ -174,7 +174,7 @@ describe('StatefulFieldsBrowser', () => { .first() .simulate('click'); expect( - wrapper.find(`.field-browser-category-pane-cloud-${timelineId}`).first() + wrapper.find(`.field-browser-category-pane-cloud-${timelineId}`).at(1) ).toHaveStyleRule('font-weight', 'normal', { modifier: '.euiText' }); wrapper .find('[data-test-subj="field-search"]') @@ -184,7 +184,7 @@ describe('StatefulFieldsBrowser', () => { jest.runOnlyPendingTimers(); wrapper.update(); expect( - wrapper.find(`.field-browser-category-pane-cloud-${timelineId}`).first() + wrapper.find(`.field-browser-category-pane-cloud-${timelineId}`).at(1) ).toHaveStyleRule('font-weight', 'bold', { modifier: '.euiText' }); }); }); diff --git a/x-pack/plugins/siem/public/timelines/components/timeline/body/column_headers/header/index.test.tsx b/x-pack/plugins/siem/public/timelines/components/timeline/body/column_headers/header/index.test.tsx index dfbb5508f27c7..a3dfd9b09f083 100644 --- a/x-pack/plugins/siem/public/timelines/components/timeline/body/column_headers/header/index.test.tsx +++ b/x-pack/plugins/siem/public/timelines/components/timeline/body/column_headers/header/index.test.tsx @@ -323,10 +323,9 @@ describe('Header', () => { ); - expect(wrapper.find(`[data-test-subj="header-text-${columnHeader.id}"]`)).toHaveStyleRule( - 'text-overflow', - 'ellipsis' - ); + expect( + wrapper.find(`[data-test-subj="header-text-${columnHeader.id}"]`).at(1) + ).toHaveStyleRule('text-overflow', 'ellipsis'); }); }); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f8ade9fad91a6..a3a134978582a 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -124,6 +124,119 @@ "advancedSettings.searchBar.unableToParseQueryErrorMessage": "クエリをパースできません", "advancedSettings.searchBarAriaLabel": "高度な設定を検索", "advancedSettings.voiceAnnouncement.searchResultScreenReaderMessage": "{query} を検索しました。{sectionLenght, plural, one {# セクション} other {# セクション}}に{optionLenght, plural, one {# オプション} other {# オプション}}があります。", + "apmOss.tutorial.apmAgents.statusCheck.btnLabel": "エージェントステータスを確認", + "apmOss.tutorial.apmAgents.statusCheck.errorMessage": "エージェントからまだデータを受け取っていません", + "apmOss.tutorial.apmAgents.statusCheck.successMessage": "1 つまたは複数のエージェントからデータを受け取りました", + "apmOss.tutorial.apmAgents.statusCheck.text": "アプリケーションが実行されていてエージェントがデータを送信していることを確認してください。", + "apmOss.tutorial.apmAgents.statusCheck.title": "エージェントステータス", + "apmOss.tutorial.apmAgents.title": "APM エージェント", + "apmOss.tutorial.apmServer.callOut.message": "ご使用の APM Server を 7.0 以上に更新してあることを確認してください。 Kibana の管理セクションにある移行アシスタントで 6.x データを移行することもできます。", + "apmOss.tutorial.apmServer.callOut.title": "重要:7.0 以上に更新中", + "apmOss.tutorial.apmServer.statusCheck.btnLabel": "APM Server ステータスを確認", + "apmOss.tutorial.apmServer.statusCheck.errorMessage": "APM Server が検出されました。7.0 以上に更新され、動作中であることを確認してください。", + "apmOss.tutorial.apmServer.statusCheck.successMessage": "APM Server が正しくセットアップされました", + "apmOss.tutorial.apmServer.statusCheck.text": "APM エージェントの導入を開始する前に、APM Server が動作していることを確認してください。", + "apmOss.tutorial.apmServer.statusCheck.title": "APM Server ステータス", + "apmOss.tutorial.apmServer.title": "APM Server", + "apmOss.tutorial.djangoClient.configure.commands.addAgentComment": "インストールされたアプリにエージェントを追加します", + "apmOss.tutorial.djangoClient.configure.commands.addTracingMiddlewareComment": "パフォーマンスメトリックを送信するには、追跡ミドルウェアを追加します。", + "apmOss.tutorial.djangoClient.configure.commands.allowedCharactersComment": "a-z、A-Z、0-9、-、_、スペース", + "apmOss.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment": "カスタム APM Server URL (デフォルト: {defaultApmServerUrl})", + "apmOss.tutorial.djangoClient.configure.commands.setRequiredServiceNameComment": "必要なサーバー名を設定します。使用できる文字:", + "apmOss.tutorial.djangoClient.configure.commands.useIfApmServerRequiresTokenComment": "APM Server にトークンが必要な場合に使います", + "apmOss.tutorial.djangoClient.configure.textPost": "高度な用途に関しては [ドキュメンテーション]({documentationLink}) をご覧ください。", + "apmOss.tutorial.djangoClient.configure.textPre": "エージェントとは、アプリケーションプロセス内で実行されるライブラリです。APM サービスは「SERVICE_NAME」に基づいてプログラムで作成されます。", + "apmOss.tutorial.djangoClient.configure.title": "エージェントの構成", + "apmOss.tutorial.djangoClient.install.textPre": "Python 用の APM エージェントを依存関係としてインストールします。", + "apmOss.tutorial.djangoClient.install.title": "APM エージェントのインストール", + "apmOss.tutorial.dotNetClient.configureAgent.textPost": "エージェントに「IConfiguration」インスタンスが渡されていない場合、(例: 非 ASP.NET Core アプリケーションの場合)、エージェントを環境変数で構成することもできます。\n 高度な用途に関しては [ドキュメンテーション]({documentationLink}) をご覧ください。", + "apmOss.tutorial.dotNetClient.configureAgent.title": "appsettings.json ファイルの例:", + "apmOss.tutorial.dotNetClient.configureApplication.textPost": "「IConfiguration」インスタンスを渡すのは任意であり、これにより、エージェントはこの「IConfiguration」インスタンス (例: 「appsettings.json」ファイル) から構成を読み込みます。", + "apmOss.tutorial.dotNetClient.configureApplication.textPre": "「Elastic.Apm.NetCoreAll」パッケージの ASP.NET Core の場合、「Startup.cs」ファイル内の「Configure」メソドの「UseElasticApm」メソドを呼び出します。", + "apmOss.tutorial.dotNetClient.configureApplication.title": "エージェントをアプリケーションに追加", + "apmOss.tutorial.dotNetClient.download.textPre": "[NuGet]({allNuGetPackagesLink}) から .NET アプリケーションにエージェントパッケージを追加してください。用途の異なる複数の NuGet パッケージがあります。\n\nEntity Framework Core の ASP.NET Core アプリケーションの場合は、[Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink}) パッケージをダウンロードしてください。このパッケージは、自動的にすべてのエージェントコンポーネントをアプリケーションに追加します。\n\n 依存性を最低限に抑えたい場合、ASP.NET Core の監視のみに [Elastic.Apm.AspNetCore]({aspNetCorePackageLink}) パッケージ、または Entity Framework Core の監視のみに [Elastic.Apm.EfCore]({efCorePackageLink}) パッケージを使用することができます。\n\n 手動インストルメンテーションのみにパブリック Agent API を使用する場合は、[Elastic.Apm]({elasticApmPackageLink}) パッケージを使用してください。", + "apmOss.tutorial.dotNetClient.download.title": "APM エージェントのダウンロード", + "apmOss.tutorial.downloadServer.title": "APM Server をダウンロードして展開します", + "apmOss.tutorial.downloadServerRpm": "32 ビットパッケージをお探しですか?[ダウンロードページ]({downloadPageLink}) をご覧ください。", + "apmOss.tutorial.downloadServerTitle": "32 ビットパッケージをお探しですか?[ダウンロードページ]({downloadPageLink}) をご覧ください。", + "apmOss.tutorial.editConfig.textPre": "Elastic Stack の X-Pack セキュアバージョンをご使用の場合、「apm-server.yml」構成ファイルで認証情報を指定する必要があります。", + "apmOss.tutorial.editConfig.title": "構成を編集する", + "apmOss.tutorial.flaskClient.configure.commands.allowedCharactersComment": "a-z、A-Z、0-9、-、_、スペース", + "apmOss.tutorial.flaskClient.configure.commands.configureElasticApmComment": "またはアプリケーションの設定で ELASTIC_APM を使用するよう構成します。", + "apmOss.tutorial.flaskClient.configure.commands.initializeUsingEnvironmentVariablesComment": "環境変数を使用して初期化します", + "apmOss.tutorial.flaskClient.configure.commands.setCustomApmServerUrlComment": "カスタム APM Server URL (デフォルト: {defaultApmServerUrl})", + "apmOss.tutorial.flaskClient.configure.commands.setRequiredServiceNameComment": "必要なサーバー名を設定します。使用できる文字:", + "apmOss.tutorial.flaskClient.configure.commands.useIfApmServerRequiresTokenComment": "APM Server にトークンが必要な場合に使います", + "apmOss.tutorial.flaskClient.configure.textPost": "高度な用途に関しては [ドキュメンテーション]({documentationLink}) をご覧ください。", + "apmOss.tutorial.flaskClient.configure.textPre": "エージェントとは、アプリケーションプロセス内で実行されるライブラリです。APM サービスは「SERVICE_NAME」に基づいてプログラムで作成されます。", + "apmOss.tutorial.flaskClient.configure.title": "エージェントの構成", + "apmOss.tutorial.flaskClient.install.textPre": "Python 用の APM エージェントを依存関係としてインストールします。", + "apmOss.tutorial.flaskClient.install.title": "APM エージェントのインストール", + "apmOss.tutorial.goClient.configure.commands.initializeUsingEnvironmentVariablesComment": "環境変数を使用して初期化します:", + "apmOss.tutorial.goClient.configure.commands.setCustomApmServerUrlComment": "カスタム APM Server URL (デフォルト: {defaultApmServerUrl})", + "apmOss.tutorial.goClient.configure.commands.setServiceNameComment": "サービス名を設定します。使用できる文字は # a-z、A-Z、0-9、-、_、スペースです。", + "apmOss.tutorial.goClient.configure.commands.usedExecutableNameComment": "ELASTIC_APM_SERVICE_NAME が指定されていない場合、実行可能な名前が使用されます。", + "apmOss.tutorial.goClient.configure.commands.useIfApmRequiresTokenComment": "APM Server にトークンが必要な場合に使います", + "apmOss.tutorial.goClient.configure.textPost": "高度な構成に関しては [ドキュメンテーション]({documentationLink}) をご覧ください。", + "apmOss.tutorial.goClient.configure.textPre": "エージェントとは、アプリケーションプロセス内で実行されるライブラリです。APM サービスは実行ファイル名または「ELASTIC_APM_SERVICE_NAME」環境変数に基づいてプログラムで作成されます。", + "apmOss.tutorial.goClient.configure.title": "エージェントの構成", + "apmOss.tutorial.goClient.install.textPre": "Go の APM エージェントパッケージをインストールします。", + "apmOss.tutorial.goClient.install.title": "APM エージェントのインストール", + "apmOss.tutorial.goClient.instrument.textPost": "Go のソースコードのインストルメンテーションの詳細ガイドは、[ドキュメンテーション]({documentationLink}) をご覧ください。", + "apmOss.tutorial.goClient.instrument.textPre": "提供されたインストルメンテーションモジュールの 1 つ、またはトレーサー API を直接使用して、Go アプリケーションにインストルメンテーションを設定します。", + "apmOss.tutorial.goClient.instrument.title": "アプリケーションのインストルメンテーション", + "apmOss.tutorial.introduction": "アプリケーション内から詳細なパフォーマンスメトリックやエラーを収集します。", + "apmOss.tutorial.javaClient.download.textPre": "[Maven Central]({mavenCentralLink}) からエージェントをダウンロードします。アプリケーションにエージェントを依存関係として「追加しない」でください。", + "apmOss.tutorial.javaClient.download.title": "APM エージェントのダウンロード", + "apmOss.tutorial.javaClient.startApplication.textPost": "構成オプションと高度な用途に関しては、[ドキュメンテーション]({documentationLink}) をご覧ください。", + "apmOss.tutorial.javaClient.startApplication.textPre": "「-javaagent」フラグを追加してエージェントをシステムプロパティで構成します。\n\n * 必要なサービス名を設定します (使用可能な文字は a-z、A-Z、0-9、-、_、スペースです)\n * カスタム APM Server URL (デフォルト: {customApmServerUrl})\n * アプリケーションのベースパッケージを設定します", + "apmOss.tutorial.javaClient.startApplication.title": "javaagent フラグでアプリケーションを起動", + "apmOss.tutorial.jsClient.enableRealUserMonitoring.textPre": "デフォルトでは、APM Server を実行すると RUM サポートは無効になります。RUM サポートを有効にする手順については、[ドキュメンテーション]({documentationLink}) をご覧ください。", + "apmOss.tutorial.jsClient.enableRealUserMonitoring.title": "APM Server のリアルユーザー監視エージェントを有効にする", + "apmOss.tutorial.jsClient.installDependency.commands.setCustomApmServerUrlComment": "カスタム APM Server URL (デフォルト: {defaultApmServerUrl})", + "apmOss.tutorial.jsClient.installDependency.commands.setRequiredServiceNameComment": "必要なサービス名を設定します (使用可能な文字は a-z、A-Z、0-9、-、_、スペースです)", + "apmOss.tutorial.jsClient.installDependency.commands.setServiceVersionComment": "サービスバージョンを設定します (ソースマップ機能に必要)", + "apmOss.tutorial.jsClient.installDependency.textPost": "React や Angular などのフレームワーク統合には、カスタム依存関係があります。詳細は [統合ドキュメント]({docLink}) をご覧ください。", + "apmOss.tutorial.jsClient.installDependency.textPre": "「npm install @elastic/apm-rum --save」でエージェントをアプリケーションへの依存関係としてインストールできます。\n\nその後で以下のようにアプリケーションでエージェントを初期化して構成できます。", + "apmOss.tutorial.jsClient.installDependency.title": "エージェントを依存関係としてセットアップ", + "apmOss.tutorial.jsClient.scriptTags.textPre": "または、スクリプトタグを使用してエージェントのセットアップと構成ができます。` を追加