[Telemetry] move from xpack main (#35403)

* enabling xpack in new plugins

* move telemetry into separate new platform plugin

* remap constants

* resolved hacks issue

* remove extra dir

* js -> ts

* run linter

* fix tests

* reset kibana.yml

* reset kibana.yml

* ts types

* add telemetry translations to i18n

* use deprecated configs

* checkout config.yml

* fix test

* move telemetry from xpack_main in api_integration

* add telemetry apis

* hide banner

* remove routes/get_stats in favor of collectors/get_stats

* code review fixes
This commit is contained in:
Ahmad Bamieh 2019-06-12 13:53:48 +03:00 committed by GitHub
parent d6cf22f9ff
commit c308048f04
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
106 changed files with 436 additions and 386 deletions

View file

@ -38,6 +38,7 @@
"xpack.ml": "x-pack/plugins/ml",
"xpack.logstash": "x-pack/plugins/logstash",
"xpack.main": "x-pack/plugins/xpack_main",
"xpack.telemetry": "x-pack/plugins/telemetry",
"xpack.monitoring": "x-pack/plugins/monitoring",
"xpack.remoteClusters": "x-pack/plugins/remote_clusters",
"xpack.reporting": "x-pack/plugins/reporting",

View file

@ -54,7 +54,7 @@ Specifies the password that {kib} uses for authentication when it retrieves data
from the monitoring cluster. If not set, {kib} uses the value of the
`elasticsearch.password` setting.
`xpack.xpack_main.telemetry.enabled`::
`xpack.telemetry.enabled`::
Set to `true` (default) to send cluster statistics to Elastic. Reporting your
cluster statistics helps us improve your user experience. Your data is never
shared with anyone. Set to `false` to disable statistics reporting from any

View file

@ -143,7 +143,7 @@ kibana_vars=(
xpack.security.encryptionKey
xpack.security.secureCookies
xpack.security.sessionTimeout
xpack.xpack_main.telemetry.enabled
xpack.telemetry.enabled
)
longopts=''

View file

@ -39,12 +39,14 @@ import { translations } from './plugins/translations';
import { upgradeAssistant } from './plugins/upgrade_assistant';
import { uptime } from './plugins/uptime';
import { ossTelemetry } from './plugins/oss_telemetry';
import { telemetry } from './plugins/telemetry';
import { encryptedSavedObjects } from './plugins/encrypted_saved_objects';
import { snapshotRestore } from './plugins/snapshot_restore';
module.exports = function (kibana) {
return [
xpackMain(kibana),
telemetry(kibana),
graph(kibana),
monitoring(kibana),
reporting(kibana),

View file

@ -4,10 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { fetchTelemetry } from '../../../xpack_main/public/hacks/fetch_telemetry';
export { PRIVACY_STATEMENT_URL } from '../../../xpack_main/common/constants';
export { TelemetryOptInProvider } from '../../../xpack_main/public/services/telemetry_opt_in';
export { OptInExampleFlyout } from '../../../xpack_main/public/components';
import { fetchTelemetry } from '../../../telemetry/public/hacks/fetch_telemetry';
export { PRIVACY_STATEMENT_URL } from '../../../telemetry/common/constants';
export { TelemetryOptInProvider } from '../../../telemetry/public/services/telemetry_opt_in';
export { OptInExampleFlyout } from '../../../telemetry/public/components';
let telemetryEnabled;
let httpClient;

View file

@ -5,7 +5,7 @@
*/
import { MONITORING_SYSTEM_API_VERSION } from '../../../common/constants';
import { KIBANA_SYSTEM_ID } from '../../../../xpack_main/common/constants';
import { KIBANA_SYSTEM_ID } from '../../../../telemetry/common/constants';
/*
* Send the Kibana usage data to the ES Monitoring Bulk endpoint

View file

@ -6,7 +6,7 @@
import { get, uniq } from 'lodash';
import { METRICBEAT_INDEX_NAME_UNIQUE_TOKEN } from '../../../../common/constants';
import { KIBANA_SYSTEM_ID, BEATS_SYSTEM_ID, LOGSTASH_SYSTEM_ID } from '../../../../../xpack_main/common/constants';
import { KIBANA_SYSTEM_ID, BEATS_SYSTEM_ID, LOGSTASH_SYSTEM_ID } from '../../../../../telemetry/common/constants';
const APM_CUSTOM_ID = 'apm';
const ELASTICSEARCH_CUSTOM_ID = 'elasticsearch';

View file

@ -16,9 +16,9 @@ export const CONFIG_TELEMETRY = 'telemetry:optIn';
* @type {string}
*/
export const getConfigTelemetryDesc = () => {
return i18n.translate('xpack.main.telemetry.telemetryConfigDescription', {
return i18n.translate('xpack.telemetry.telemetryConfigDescription', {
defaultMessage:
'Help us improve the Elastic Stack by providing usage statistics for basic features. We will not share this data outside of Elastic.'
'Help us improve the Elastic Stack by providing usage statistics for basic features. We will not share this data outside of Elastic.',
});
};

View file

@ -0,0 +1,15 @@
/*
* 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 { KibanaConfig } from 'src/legacy/server/kbn_server';
export function getXpackConfigWithDeprecated(config: KibanaConfig, configPath: string) {
const deprecatedConfig = config.get(`xpack.xpack_main.${configPath}`);
if (typeof deprecatedConfig !== 'undefined') {
return deprecatedConfig;
}
return config.get(`xpack.${configPath}`);
}

View file

@ -0,0 +1,95 @@
/*
* 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 { resolve } from 'path';
import JoiNamespace from 'joi';
import { Server } from 'hapi';
import { CoreSetup, PluginInitializerContext } from 'src/core/server';
import { i18n } from '@kbn/i18n';
import mappings from './mappings.json';
import { CONFIG_TELEMETRY, getConfigTelemetryDesc, REPORT_INTERVAL_MS } from './common/constants';
import { getXpackConfigWithDeprecated } from './common/get_xpack_config_with_deprecated';
import { telemetryPlugin } from './server';
import {
createLocalizationUsageCollector,
createTelemetryUsageCollector,
} from './server/collectors';
const ENDPOINT_VERSION = 'v2';
export const telemetry = (kibana: any) => {
return new kibana.Plugin({
id: 'telemetry',
configPrefix: 'xpack.telemetry',
publicDir: resolve(__dirname, 'public'),
require: ['elasticsearch'],
config(Joi: typeof JoiNamespace) {
return Joi.object({
enabled: Joi.boolean().default(true),
// `config` is used internally and not intended to be set
config: Joi.string().default(Joi.ref('$defaultConfigPath')),
url: Joi.when('$dev', {
is: true,
then: Joi.string().default(
`https://telemetry-staging.elastic.co/xpack/${ENDPOINT_VERSION}/send`
),
otherwise: Joi.string().default(
`https://telemetry.elastic.co/xpack/${ENDPOINT_VERSION}/send`
),
}),
}).default();
},
uiExports: {
managementSections: ['plugins/telemetry/views/management'],
uiSettingDefaults: {
[CONFIG_TELEMETRY]: {
name: i18n.translate('xpack.telemetry.telemetryConfigTitle', {
defaultMessage: 'Telemetry opt-in',
}),
description: getConfigTelemetryDesc(),
value: false,
readonly: true,
},
},
savedObjectSchemas: {
telemetry: {
isNamespaceAgnostic: true,
},
},
injectDefaultVars(server: Server) {
const config = server.config();
return {
telemetryEnabled: getXpackConfigWithDeprecated(config, 'telemetry.enabled'),
telemetryUrl: getXpackConfigWithDeprecated(config, 'telemetry.url'),
spacesEnabled: config.get('xpack.spaces.enabled'),
telemetryOptedIn: null,
activeSpace: null,
};
},
hacks: [
'plugins/telemetry/hacks/telemetry_opt_in',
'plugins/telemetry/hacks/telemetry_trigger',
],
mappings,
},
init(server: Server) {
const initializerContext = {} as PluginInitializerContext;
const coreSetup = ({
http: { server },
} as any) as CoreSetup;
telemetryPlugin(initializerContext).setup(coreSetup);
// register collectors
server.usage.collectorSet.register(createLocalizationUsageCollector(server));
server.usage.collectorSet.register(createTelemetryUsageCollector(server));
// expose
server.expose('telemetryCollectionInterval', REPORT_INTERVAL_MS);
},
});
};

View file

@ -15,7 +15,7 @@ exports[`OptInDetailsComponent renders as expected 1`] = `
<h2>
<FormattedMessage
defaultMessage="Cluster statistics"
id="xpack.main.telemetry.callout.clusterStatisticsTitle"
id="xpack.telemetry.callout.clusterStatisticsTitle"
values={Object {}}
/>
</h2>
@ -26,7 +26,7 @@ exports[`OptInDetailsComponent renders as expected 1`] = `
<EuiText>
<FormattedMessage
defaultMessage="This is an example of the basic cluster statistics that we'll collect. It includes the number of indices, shards, and nodes. It also includes high-level usage statistics, such as whether monitoring is turned on."
id="xpack.main.telemetry.callout.clusterStatisticsDescription"
id="xpack.telemetry.callout.clusterStatisticsDescription"
values={Object {}}
/>
</EuiText>

View file

@ -18,7 +18,7 @@ exports[`TelemetryForm renders as expected 1`] = `
<h2>
<FormattedMessage
defaultMessage="Usage Data"
id="xpack.main.telemetry.usageDataTitle"
id="xpack.telemetry.usageDataTitle"
values={Object {}}
/>
</h2>
@ -47,7 +47,7 @@ exports[`TelemetryForm renders as expected 1`] = `
>
<FormattedMessage
defaultMessage="See an example of what we collect"
id="xpack.main.telemetry.seeExampleOfWhatWeCollectLinkText"
id="xpack.telemetry.seeExampleOfWhatWeCollectLinkText"
values={Object {}}
/>
</EuiLink>
@ -61,7 +61,7 @@ exports[`TelemetryForm renders as expected 1`] = `
>
<FormattedMessage
defaultMessage="Read our usage data privacy statement"
id="xpack.main.telemetry.readOurUsageDataPrivacyStatementLinkText"
id="xpack.telemetry.readOurUsageDataPrivacyStatementLinkText"
values={Object {}}
/>
</EuiLink>

View file

@ -4,4 +4,5 @@
* you may not use this file except in compliance with the Elastic License.
*/
export { telemetryRoute } from './telemetry';
export { TelemetryForm } from './telemetry_form';
export { OptInExampleFlyout } from './opt_in_details_component';

View file

@ -80,14 +80,14 @@ export class OptInExampleFlyout extends Component {
return (
<EuiCallOut
title={<FormattedMessage
id="xpack.main.telemetry.callout.errorUnprivilegedUserTitle"
id="xpack.telemetry.callout.errorUnprivilegedUserTitle"
defaultMessage="Error displaying cluster statistics"
/>}
color="danger"
iconType="cross"
>
<FormattedMessage
id="xpack.main.telemetry.callout.errorUnprivilegedUserDescription"
id="xpack.telemetry.callout.errorUnprivilegedUserDescription"
defaultMessage="You do not have access to see unencrypted cluster statistics."
/>
</EuiCallOut>
@ -98,14 +98,14 @@ export class OptInExampleFlyout extends Component {
return (
<EuiCallOut
title={<FormattedMessage
id="xpack.main.telemetry.callout.errorLoadingClusterStatisticsTitle"
id="xpack.telemetry.callout.errorLoadingClusterStatisticsTitle"
defaultMessage="Error loading cluster statistics"
/>}
color="danger"
iconType="cross"
>
<FormattedMessage
id="xpack.main.telemetry.callout.errorLoadingClusterStatisticsDescription"
id="xpack.telemetry.callout.errorLoadingClusterStatisticsDescription"
defaultMessage="An unexpected error occured while attempting to fetch the cluster statistics.
This can occur because Elasticsearch failed, Kibana failed, or there is a network error.
Check Kibana, then reload the page and try again."
@ -133,7 +133,7 @@ export class OptInExampleFlyout extends Component {
<EuiTitle>
<h2>
<FormattedMessage
id="xpack.main.telemetry.callout.clusterStatisticsTitle"
id="xpack.telemetry.callout.clusterStatisticsTitle"
defaultMessage="Cluster statistics"
/>
</h2>
@ -141,7 +141,7 @@ export class OptInExampleFlyout extends Component {
<EuiTextColor color="subdued">
<EuiText>
<FormattedMessage
id="xpack.main.telemetry.callout.clusterStatisticsDescription"
id="xpack.telemetry.callout.clusterStatisticsDescription"
defaultMessage="This is an example of the basic cluster statistics that we'll collect.
It includes the number of indices, shards, and nodes.
It also includes high-level usage statistics, such as whether monitoring is turned on."

View file

@ -16,7 +16,7 @@ import {
EuiSpacer,
EuiText,
} from '@elastic/eui';
import { getConfigTelemetryDesc, PRIVACY_STATEMENT_URL } from '../../../common/constants';
import { getConfigTelemetryDesc, PRIVACY_STATEMENT_URL } from '../../common/constants';
import { OptInExampleFlyout } from './opt_in_details_component';
import { Field } from 'ui/management';
import { FormattedMessage } from '@kbn/i18n/react';
@ -85,7 +85,7 @@ export class TelemetryForm extends Component {
<EuiFlexItem grow={false}>
<h2>
<FormattedMessage
id="xpack.main.telemetry.usageDataTitle"
id="xpack.telemetry.usageDataTitle"
defaultMessage="Usage Data"
/>
</h2>
@ -123,13 +123,13 @@ export class TelemetryForm extends Component {
title={
<p>
<FormattedMessage
id="xpack.main.telemetry.callout.appliesSettingTitle"
id="xpack.telemetry.callout.appliesSettingTitle"
defaultMessage="This setting applies to {allOfKibanaText}"
values={{
allOfKibanaText: (
<strong>
<FormattedMessage
id="xpack.main.telemetry.callout.appliesSettingTitle.allOfKibanaText"
id="xpack.telemetry.callout.appliesSettingTitle.allOfKibanaText"
defaultMessage="all of Kibana."
/>
</strong>
@ -148,7 +148,7 @@ export class TelemetryForm extends Component {
<p>
<EuiLink onClick={this.toggleExample}>
<FormattedMessage
id="xpack.main.telemetry.seeExampleOfWhatWeCollectLinkText"
id="xpack.telemetry.seeExampleOfWhatWeCollectLinkText"
defaultMessage="See an example of what we collect"
/>
</EuiLink>
@ -156,7 +156,7 @@ export class TelemetryForm extends Component {
<p>
<EuiLink href={PRIVACY_STATEMENT_URL} target="_blank">
<FormattedMessage
id="xpack.main.telemetry.readOurUsageDataPrivacyStatementLinkText"
id="xpack.telemetry.readOurUsageDataPrivacyStatementLinkText"
defaultMessage="Read our usage data privacy statement"
/>
</EuiLink>

View file

@ -7,7 +7,7 @@
import React from 'react';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { TelemetryForm } from './telemetry_form';
import { TelemetryOptInProvider } from '../../services/telemetry_opt_in';
import { TelemetryOptInProvider } from '../services/telemetry_opt_in';
const buildTelemetryOptInProvider = () => {
const mockHttp = {

View file

@ -8,4 +8,4 @@ import { uiModules } from 'ui/modules';
import { injectBanner } from './welcome_banner';
uiModules.get('xpack_main/hacks').run(injectBanner);
uiModules.get('telemetry/hacks').run(injectBanner);

View file

@ -8,9 +8,10 @@ import { uiModules } from 'ui/modules';
import { Path } from 'plugins/xpack_main/services/path';
import { Telemetry } from './telemetry';
import { fetchTelemetry } from './fetch_telemetry';
import { npStart } from 'ui/new_platform';
function telemetryStart($injector) {
const telemetryEnabled = $injector.get('telemetryEnabled');
const telemetryEnabled = npStart.core.injectedMetadata.getInjectedVar('telemetryEnabled');
if (telemetryEnabled) {
// no telemetry for non-logged in users
@ -23,4 +24,4 @@ function telemetryStart($injector) {
}
}
uiModules.get('xpack_main/hacks').run(telemetryStart);
uiModules.get('telemetry/hacks').run(telemetryStart);

View file

@ -43,7 +43,7 @@ export async function clickBanner(
_toastNotifications.addDanger({
title: (
<FormattedMessage
id="xpack.main.telemetry.telemetryErrorNotificationMessageTitle"
id="xpack.telemetry.telemetryErrorNotificationMessageTitle"
defaultMessage="Telemetry Error"
/>
),
@ -51,13 +51,13 @@ export async function clickBanner(
<EuiText>
<p>
<FormattedMessage
id="xpack.main.telemetry.telemetryErrorNotificationMessageDescription.unableToSaveTelemetryPreferenceText"
id="xpack.telemetry.telemetryErrorNotificationMessageDescription.unableToSaveTelemetryPreferenceText"
defaultMessage="Unable to save telemetry preference."
/>
</p>
<EuiText size="xs">
<FormattedMessage
id="xpack.main.telemetry.telemetryErrorNotificationMessageDescription.tryAgainText"
id="xpack.telemetry.telemetryErrorNotificationMessageDescription.tryAgainText"
defaultMessage="Check that Kibana and Elasticsearch are still running, then try again."
/>
</EuiText>

View file

@ -10,6 +10,7 @@ import { fetchTelemetry } from '../fetch_telemetry';
import { renderBanner } from './render_banner';
import { shouldShowBanner } from './should_show_banner';
import { TelemetryOptInProvider } from '../../services/telemetry_opt_in';
import { npStart } from 'ui/new_platform';
/**
* Add the Telemetry opt-in banner if the user has not already made a decision.
@ -20,16 +21,10 @@ import { TelemetryOptInProvider } from '../../services/telemetry_opt_in';
* @param {Object} $injector The Angular injector
*/
async function asyncInjectBanner($injector) {
const telemetryEnabled = $injector.get('telemetryEnabled');
const Private = $injector.get('Private');
const telemetryOptInProvider = Private(TelemetryOptInProvider);
const config = $injector.get('config');
// no banner if the server config has telemetry disabled
if (!telemetryEnabled) {
return;
}
// and no banner for non-logged in users
if (Path.isUnauthenticated()) {
return;
@ -54,5 +49,9 @@ async function asyncInjectBanner($injector) {
* @param {Object} $injector The Angular injector
*/
export function injectBanner($injector) {
asyncInjectBanner($injector);
const telemetryEnabled = npStart.core.injectedMetadata.getInjectedVar('telemetryEnabled');
const telemetryBanner = npStart.core.injectedMetadata.getInjectedVar('telemetryBanner');
if (telemetryEnabled && telemetryBanner) {
asyncInjectBanner($injector);
}
}

View file

@ -58,7 +58,7 @@ export class OptInBanner extends Component {
<EuiText>
<p tabIndex="0">
<FormattedMessage
id="xpack.main.welcomeBanner.telemetryConfigDetailsDescription"
id="xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription"
defaultMessage="No information about the data you process or store will be sent. This feature
will periodically send basic feature usage statistics. See an {exampleLink} or read our {telemetryPrivacyStatementLink}.
You can disable this feature at any time."
@ -66,7 +66,7 @@ export class OptInBanner extends Component {
exampleLink: (
<EuiLink onClick={() => this.setState({ showExample: !this.state.showExample })}>
<FormattedMessage
id="xpack.main.welcomeBanner.telemetryConfigDetailsDescription.exampleLinkText"
id="xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription.exampleLinkText"
defaultMessage="example"
/>
</EuiLink>
@ -74,7 +74,7 @@ export class OptInBanner extends Component {
telemetryPrivacyStatementLink: (
<EuiLink href={PRIVACY_STATEMENT_URL} target="_blank" >
<FormattedMessage
id="xpack.main.welcomeBanner.telemetryConfigDetailsDescription.telemetryPrivacyStatementLinkText"
id="xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription.telemetryPrivacyStatementLinkText"
defaultMessage="telemetry privacy statement"
/>
</EuiLink>
@ -99,7 +99,7 @@ export class OptInBanner extends Component {
{getConfigTelemetryDesc()} {(
<EuiLink onClick={() => this.setState({ showDetails: true })}>
<FormattedMessage
id="xpack.main.welcomeBanner.telemetryConfigDescription.readMoreLinkText"
id="xpack.telemetry.welcomeBanner.telemetryConfigDescription.readMoreLinkText"
defaultMessage="Read more"
/>
</EuiLink>
@ -124,7 +124,7 @@ export class OptInBanner extends Component {
onClick={() => this.props.optInClick(true)}
>
<FormattedMessage
id="xpack.main.welcomeBanner.yesButtonLabel"
id="xpack.telemetry.welcomeBanner.yesButtonLabel"
defaultMessage="Yes"
/>
</EuiButton>
@ -135,7 +135,7 @@ export class OptInBanner extends Component {
onClick={() => this.props.optInClick(false)}
>
<FormattedMessage
id="xpack.main.welcomeBanner.noButtonLabel"
id="xpack.telemetry.welcomeBanner.noButtonLabel"
defaultMessage="No"
/>
</EuiButton>

View file

@ -25,10 +25,10 @@ export function TelemetryOptInProvider($injector, chrome) {
currentOptInStatus = enabled;
} catch (error) {
toastNotifications.addError(error, {
title: i18n.translate('xpack.main.telemetry.optInErrorToastTitle', {
title: i18n.translate('xpack.telemetry.optInErrorToastTitle', {
defaultMessage: 'Error',
}),
toastMessage: i18n.translate('xpack.main.telemetry.optInErrorToastText', {
toastMessage: i18n.translate('xpack.telemetry.optInErrorToastText', {
defaultMessage: 'An error occured while trying to set the usage statistics preference.',
}),
});

View file

@ -0,0 +1,46 @@
/*
* 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 { getAllStats, getLocalStats } from './';
/**
* Get the telemetry data.
*
* @param {Object} req The incoming request.
* @param {Object} config Kibana config.
* @param {String} start The start time of the request (likely 20m ago).
* @param {String} end The end time of the request.
* @param {Boolean} unencrypted Is the request payload going to be unencrypted.
* @return {Promise} An array of telemetry objects.
*/
export async function getStats(
req: any,
config: any,
start: string,
end: string,
unencrypted: boolean,
statsGetters: any = {}
) {
const { _getAllStats = getAllStats, _getLocalStats = getLocalStats } = statsGetters;
let response = [];
const useInternalUser = !unencrypted;
if (config.get('xpack.monitoring.enabled')) {
try {
// attempt to collect stats from multiple clusters in monitoring data
response = await _getAllStats(req, start, end, { useInternalUser });
} catch (err) {
// no-op
}
}
if (!Array.isArray(response) || response.length === 0) {
// return it as an array for a consistent API response
response = [await _getLocalStats(req, { useInternalUser })];
}
return response;
}

View file

@ -4,7 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
// @ts-ignore
export { getAllStats } from './monitoring';
// @ts-ignore
export { getLocalStats } from './local';
export { getStats } from './get_stats';
export { encryptTelemetry } from './encryption';
export { createTelemetryUsageCollector } from './usage';
export { createLocalizationUsageCollector } from './localization';

View file

@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
export { telemetryRoute } from './telemetry';
export { createLocalizationUsageCollector } from './telemetry_localization_collector';

View file

@ -18,7 +18,7 @@ const createI18nLoaderMock = (translations: TranslationsMock) => {
};
};
import { getTranslationCount } from './get_localization_usage_collector';
import { getTranslationCount } from './telemetry_localization_collector';
describe('getTranslationCount', () => {
it('returns 0 if no translations registered', async () => {

View file

@ -6,10 +6,8 @@
import { i18nLoader } from '@kbn/i18n';
import { size } from 'lodash';
// @ts-ignore
import { KIBANA_LOCALIZATION_STATS_TYPE } from '../../common/constants';
import { getIntegrityHashes, Integrities } from './file_integrity';
import { KIBANA_LOCALIZATION_STATS_TYPE } from '../../../common/constants';
export interface UsageStats {
locale: string;
integrities: Integrities;
@ -44,7 +42,7 @@ export function createCollectorFetch(server: any) {
* @param {Object} server
* @return {Object} kibana usage stats type collection object
*/
export function getLocalizationUsageCollector(server: any) {
export function createLocalizationUsageCollector(server: any) {
const { collectorSet } = server.usage;
return collectorSet.makeUsageCollector({
type: KIBANA_LOCALIZATION_STATS_TYPE,

View file

@ -5,17 +5,15 @@
*/
import { get, set, merge } from 'lodash';
import {
KIBANA_SYSTEM_ID,
LOGSTASH_SYSTEM_ID,
BEATS_SYSTEM_ID,
} from '../../../../common/constants';
import { constants } from '../../';
import { getClusterUuids } from './get_cluster_uuids';
import { getElasticsearchStats } from './get_es_stats';
import { getKibanaStats } from './get_kibana_stats';
import { getBeatsStats } from './get_beats_stats';
import { getHighLevelStats } from './get_high_level_stats';
/**
* Get statistics for all products joined by Elasticsearch cluster.
*
@ -66,7 +64,7 @@ function getAllStatsWithCaller(server, callCluster, start, end) {
return Promise.all([
getElasticsearchStats(server, callCluster, clusterUuids), // cluster_stats, stack_stats.xpack, cluster_name/uuid, license, version
getKibanaStats(server, callCluster, clusterUuids, start, end), // stack_stats.kibana
getHighLevelStats(server, callCluster, clusterUuids, start, end, LOGSTASH_SYSTEM_ID), // stack_stats.logstash
getHighLevelStats(server, callCluster, clusterUuids, start, end, constants.LOGSTASH_SYSTEM_ID), // stack_stats.logstash
getBeatsStats(server, callCluster, clusterUuids, start, end), // stack_stats.beats
])
.then(([esClusters, kibana, logstash, beats]) => handleAllStats(esClusters, { kibana, logstash, beats }));
@ -85,9 +83,9 @@ function getAllStatsWithCaller(server, callCluster, start, end) {
export function handleAllStats(clusters, { kibana, logstash, beats }) {
return clusters.map(cluster => {
// if they are using Kibana or Logstash, then add it to the cluster details under cluster.stack_stats
addStackStats(cluster, kibana, KIBANA_SYSTEM_ID);
addStackStats(cluster, logstash, LOGSTASH_SYSTEM_ID);
addStackStats(cluster, beats, BEATS_SYSTEM_ID);
addStackStats(cluster, kibana, constants.KIBANA_SYSTEM_ID);
addStackStats(cluster, logstash, constants.LOGSTASH_SYSTEM_ID);
addStackStats(cluster, beats, constants.BEATS_SYSTEM_ID);
mergeXPackStats(cluster, kibana, 'graph_workspace', 'graph'); // copy graph_workspace info out of kibana, merge it into stack_stats.xpack.graph
return cluster;

View file

@ -6,7 +6,7 @@
import { get } from 'lodash';
import { createQuery } from './create_query';
import { INDEX_PATTERN_BEATS } from '../../../../../monitoring/common/constants';
import { INDEX_PATTERN_BEATS } from '../../../../monitoring/common/constants';
const HITS_SIZE = 10000; // maximum hits to receive from ES with each search

View file

@ -6,7 +6,7 @@
import { get } from 'lodash';
import { createQuery } from './create_query';
import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../monitoring/common/constants';
import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../monitoring/common/constants';
/**
* Get a list of Cluster UUIDs that exist within the specified timespan.

View file

@ -5,7 +5,7 @@
*/
import { get } from 'lodash';
import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../monitoring/common/constants';
import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../monitoring/common/constants';
/**
* Get statistics for all selected Elasticsearch clusters.

View file

@ -6,8 +6,8 @@
import { get } from 'lodash';
import { createQuery } from './create_query';
import { INDEX_PATTERN_KIBANA, INDEX_PATTERN_BEATS, INDEX_PATTERN_LOGSTASH } from '../../../../../monitoring/common/constants';
import { KIBANA_SYSTEM_ID, BEATS_SYSTEM_ID, APM_SYSTEM_ID, LOGSTASH_SYSTEM_ID, TELEMETRY_QUERY_SOURCE } from '../../../../common/constants';
import { INDEX_PATTERN_KIBANA, INDEX_PATTERN_BEATS, INDEX_PATTERN_LOGSTASH } from '../../../../monitoring/common/constants';
import { KIBANA_SYSTEM_ID, BEATS_SYSTEM_ID, APM_SYSTEM_ID, LOGSTASH_SYSTEM_ID, TELEMETRY_QUERY_SOURCE } from '../../../common/constants';
/**
* Update a counter associated with the {@code key}.

View file

@ -5,7 +5,7 @@
*/
import { get, isEmpty, omit } from 'lodash';
import { KIBANA_SYSTEM_ID } from '../../../../common/constants';
import { KIBANA_SYSTEM_ID } from '../../../common/constants';
import { fetchHighLevelStats, handleHighLevelStatsResponse } from './get_high_level_stats';
export function rollUpTotals(rolledUp, addOn, field) {

View file

@ -28,8 +28,8 @@ const serverWithConfig = (configPath: string): KibanaHapiServer & Server => {
...getMockServer(),
config: () => ({
get: (key: string) => {
if (key !== 'xpack.xpack_main.telemetry.config') {
throw new Error('Expected `xpack.xpack_main.telemetry.config`');
if (key !== 'xpack.telemetry.config' && key !== 'xpack.xpack_main.telemetry.config') {
throw new Error('Expected `xpack.telemetry.config`');
}
return configPath;

View file

@ -11,6 +11,7 @@ import { dirname, join } from 'path';
// look for telemetry.yml in the same places we expect kibana.yml
import { ensureDeepObject } from './ensure_deep_object';
import { getXpackConfigWithDeprecated } from '../../../common/get_xpack_config_with_deprecated';
/**
* The maximum file size before we ignore it (note: this limit is arbitrary).
@ -85,7 +86,8 @@ export function createTelemetryUsageCollector(server: KibanaHapiServer) {
type: 'static_telemetry',
isReady: () => true,
fetch: async () => {
const configPath: string = server.config().get('xpack.xpack_main.telemetry.config');
const config = server.config();
const configPath = getXpackConfigWithDeprecated(config, 'telemetry.config') as string;
const telemetryPath = join(dirname(configPath), 'telemetry.yml');
return await readTelemetryFile(telemetryPath);
},

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
export async function getTelemetryOptIn(request) {
export async function getTelemetryOptIn(request: any) {
const isRequestingApplication = request.path.startsWith('/app');
// Prevent interstitial screens (such as the space selector) from prompting for telemetry

View file

@ -0,0 +1,14 @@
/*
* 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 { PluginInitializerContext } from 'src/core/server';
import { TelemetryPlugin } from './plugin';
import * as constants from '../common/constants';
export { getTelemetryOptIn } from './get_telemetry_opt_in';
export const telemetryPlugin = (initializerContext: PluginInitializerContext) =>
new TelemetryPlugin();
export { constants };

View file

@ -0,0 +1,14 @@
/*
* 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 { CoreSetup } from 'src/core/server';
import { registerRoutes } from './routes';
export class TelemetryPlugin {
public setup(core: CoreSetup) {
registerRoutes(core);
}
}

View file

@ -0,0 +1,14 @@
/*
* 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 { CoreSetup } from 'src/core/server';
import { registerOptInRoutes } from './opt_in';
import { registerTelemetryDataRoutes } from './telemetry_stats';
export function registerRoutes(core: CoreSetup) {
registerOptInRoutes(core);
registerTelemetryDataRoutes(core);
}

View file

@ -0,0 +1,43 @@
/*
* 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 Joi from 'joi';
import { boomify } from 'boom';
import { CoreSetup } from 'src/core/server';
export function registerOptInRoutes(core: CoreSetup) {
const { server } = core.http as any;
server.route({
method: 'POST',
path: '/api/telemetry/v2/optIn',
options: {
validate: {
payload: Joi.object({
enabled: Joi.bool().required(),
}),
},
},
handler: async (req: any, h: any) => {
const savedObjectsClient = req.getSavedObjectsClient();
try {
await savedObjectsClient.create(
'telemetry',
{
enabled: req.payload.enabled,
},
{
id: 'telemetry',
overwrite: true,
}
);
} catch (err) {
return boomify(err);
}
return h.response({}).code(200);
},
});
}

View file

@ -0,0 +1,52 @@
/*
* 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 Joi from 'joi';
import { boomify } from 'boom';
import { CoreSetup } from 'src/core/server';
import { getStats, encryptTelemetry } from '../collectors';
export function registerTelemetryDataRoutes(core: CoreSetup) {
const { server } = core.http as any;
server.route({
method: 'POST',
path: '/api/telemetry/v2/clusters/_stats',
config: {
validate: {
payload: Joi.object({
unencrypted: Joi.bool(),
timeRange: Joi.object({
min: Joi.date().required(),
max: Joi.date().required(),
}).required(),
}),
},
},
handler: async (req: any, h: any) => {
const config = req.server.config();
const start = req.payload.timeRange.min;
const end = req.payload.timeRange.max;
const unencrypted = req.payload.unencrypted;
const isDev = config.get('env.dev');
try {
const usageData = await getStats(req, config, start, end, unencrypted);
if (unencrypted) return usageData;
return encryptTelemetry(usageData, isDev);
} catch (err) {
if (isDev) {
// don't ignore errors when running in dev mode
return boomify(err, { statusCode: err.status });
} else {
const statusCode = unencrypted && err.status === 403 ? 403 : 200;
// ignore errors and return empty set
return h.response([]).code(statusCode);
}
}
},
});
}

View file

@ -5226,31 +5226,31 @@
"xpack.main.featureRegistry.indexPatternFeatureName": "インデックスパターン管理",
"xpack.main.featureRegistry.savedObjectsManagementFeatureName": "保存されたオブジェクトの管理",
"xpack.main.featureRegistry.visualizeFeatureName": "可視化",
"xpack.main.telemetry.callout.appliesSettingTitle": "この設定は {allOfKibanaText} に適用されます",
"xpack.main.telemetry.callout.appliesSettingTitle.allOfKibanaText": "Kibana のすべて",
"xpack.main.telemetry.callout.clusterStatisticsDescription": "これは収集される基本的なクラスター統計の例です。インデックス、チャート、ノードの数が含まれます。監視がオンになっているかどうかなどのハイレベルの使用統計も含まれます。",
"xpack.main.telemetry.callout.clusterStatisticsTitle": "クラスター統計",
"xpack.main.telemetry.callout.errorLoadingClusterStatisticsDescription": "クラスター統計の取得中に予期せぬエラーが発生しました。Elasticsearch、Kibana、またはネットワークのエラーが原因の可能性があります。Kibana を確認し、ページを再読み込みして再試行してください。",
"xpack.main.telemetry.callout.errorLoadingClusterStatisticsTitle": "クラスター統計の読み込みエラー",
"xpack.main.telemetry.readOurUsageDataPrivacyStatementLinkText": "使用データのプライバシーステートメントをお読みください",
"xpack.main.telemetry.seeExampleOfWhatWeCollectLinkText": "収集されるデータの例を見る",
"xpack.main.telemetry.telemetryConfigDescription": "基本機能の使用統計を提供して Elastic Stack の改善にご協力ください。このデータは Elastic 社外と共有されません。",
"xpack.main.telemetry.telemetryConfigTitle": "遠隔測定オプトイン",
"xpack.main.telemetry.telemetryErrorNotificationMessageDescription.tryAgainText": "Kibana と Elasticsearch が現在も実行中であることを確認し、再試行してください。",
"xpack.main.telemetry.telemetryErrorNotificationMessageDescription.unableToSaveTelemetryPreferenceText": "遠隔測定設定を保存できません。",
"xpack.main.telemetry.telemetryErrorNotificationMessageTitle": "遠隔測定エラー",
"xpack.main.telemetry.usageDataTitle": "使用データ",
"xpack.telemetry.callout.appliesSettingTitle": "この設定は {allOfKibanaText} に適用されます",
"xpack.telemetry.callout.appliesSettingTitle.allOfKibanaText": "Kibana のすべて",
"xpack.telemetry.callout.clusterStatisticsDescription": "これは収集される基本的なクラスター統計の例です。インデックス、チャート、ノードの数が含まれます。監視がオンになっているかどうかなどのハイレベルの使用統計も含まれます。",
"xpack.telemetry.callout.clusterStatisticsTitle": "クラスター統計",
"xpack.telemetry.callout.errorLoadingClusterStatisticsDescription": "クラスター統計の取得中に予期せぬエラーが発生しました。Elasticsearch、Kibana、またはネットワークのエラーが原因の可能性があります。Kibana を確認し、ページを再読み込みして再試行してください。",
"xpack.telemetry.callout.errorLoadingClusterStatisticsTitle": "クラスター統計の読み込みエラー",
"xpack.telemetry.readOurUsageDataPrivacyStatementLinkText": "使用データのプライバシーステートメントをお読みください",
"xpack.telemetry.seeExampleOfWhatWeCollectLinkText": "収集されるデータの例を見る",
"xpack.telemetry.telemetryConfigDescription": "基本機能の使用統計を提供して Elastic Stack の改善にご協力ください。このデータは Elastic 社外と共有されません。",
"xpack.telemetry.telemetryConfigTitle": "遠隔測定オプトイン",
"xpack.telemetry.telemetryErrorNotificationMessageDescription.tryAgainText": "Kibana と Elasticsearch が現在も実行中であることを確認し、再試行してください。",
"xpack.telemetry.telemetryErrorNotificationMessageDescription.unableToSaveTelemetryPreferenceText": "遠隔測定設定を保存できません。",
"xpack.telemetry.telemetryErrorNotificationMessageTitle": "遠隔測定エラー",
"xpack.telemetry.usageDataTitle": "使用データ",
"xpack.main.uiSettings.adminEmailDescription": "監視からのクラスターアラートメール通知など、X-Pack 管理オペレーションの送信先のメールアドレスです。",
"xpack.main.uiSettings.adminEmailTitle": "管理者メール",
"xpack.main.welcomeBanner.licenseIsExpiredDescription": "管理者または {updateYourLicenseLinkText} に直接お問い合わせください。",
"xpack.main.welcomeBanner.licenseIsExpiredDescription.updateYourLicenseLinkText": "ライセンスを更新",
"xpack.main.welcomeBanner.licenseIsExpiredTitle": "ご使用の {licenseType} ライセンスは期限切れです",
"xpack.main.welcomeBanner.noButtonLabel": "いいえ",
"xpack.main.welcomeBanner.telemetryConfigDescription.readMoreLinkText": "詳細",
"xpack.main.welcomeBanner.telemetryConfigDetailsDescription": "ユーザーが処理したり保管したりするデータに関する情報は一切送信されません。この機能は定期的に基本機能の使用統計を送信します。{exampleLink} をご覧いただくか、{telemetryPrivacyStatementLink} をお読みください。この機能はいつでも無効にできます。",
"xpack.main.welcomeBanner.telemetryConfigDetailsDescription.exampleLinkText": "例",
"xpack.main.welcomeBanner.telemetryConfigDetailsDescription.telemetryPrivacyStatementLinkText": "遠隔測定に関するプライバシーステートメント",
"xpack.main.welcomeBanner.yesButtonLabel": "はい",
"xpack.telemetry.welcomeBanner.noButtonLabel": "いいえ",
"xpack.telemetry.welcomeBanner.telemetryConfigDescription.readMoreLinkText": "詳細",
"xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription": "ユーザーが処理したり保管したりするデータに関する情報は一切送信されません。この機能は定期的に基本機能の使用統計を送信します。{exampleLink} をご覧いただくか、{telemetryPrivacyStatementLink} をお読みください。この機能はいつでも無効にできます。",
"xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription.exampleLinkText": "例",
"xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription.telemetryPrivacyStatementLinkText": "遠隔測定に関するプライバシーステートメント",
"xpack.telemetry.welcomeBanner.yesButtonLabel": "はい",
"xpack.maps.addLayerPanel.addLayerButtonLabel": "レイヤーを追加",
"xpack.maps.addLayerPanel.cancelButtonLabel": "キャンセル",
"xpack.maps.addLayerPanel.changeDataSourceButtonLabel": "データソースを変更",

View file

@ -4367,31 +4367,31 @@
"xpack.logstash.upgradeFailureActions.goBackButtonLabel": "返回",
"xpack.logstash.upstreamPipelineArgumentMustContainAnIdPropertyErrorMessage": "upstreamPipeline 参数必须包含 id 属性",
"xpack.logstash.workersTooltip": "并行执行管道的筛选和输出阶段的工作线程数目。如果您发现事件出现积压或 CPU 未饱和,请考虑增大此数值,以更好地利用机器处理能力。\n\n默认值主机的 CPU 核心数",
"xpack.main.telemetry.callout.appliesSettingTitle": "此设置适用于{allOfKibanaText}",
"xpack.main.telemetry.callout.appliesSettingTitle.allOfKibanaText": "所有 Kibana。",
"xpack.main.telemetry.callout.clusterStatisticsDescription": "这是我们将收集的基本集群统计信息的示例。其包括索引、分片和节点的数目。还包括高级使用情况统计信息,例如监测是否打开。",
"xpack.main.telemetry.callout.clusterStatisticsTitle": "集群统计信息",
"xpack.main.telemetry.callout.errorLoadingClusterStatisticsDescription": "尝试提取集群统计信息时发生意外错误。发生此问题的原因可能是 Elasticsearch 出故障、Kibana 出故障,或者有网络错误。检查 Kibana然后重新加载页面并重试。",
"xpack.main.telemetry.callout.errorLoadingClusterStatisticsTitle": "加载集群统计信息时出错",
"xpack.main.telemetry.readOurUsageDataPrivacyStatementLinkText": "阅读我们的使用情况数据隐私声明",
"xpack.main.telemetry.seeExampleOfWhatWeCollectLinkText": "查看我们收集的内容示例",
"xpack.main.telemetry.telemetryConfigDescription": "通过提供基本功能的使用情况统计信息,来帮助我们改进 Elastic Stack。我们不会在 Elastic 之外共享此数据。",
"xpack.main.telemetry.telemetryConfigTitle": "遥测选择加入",
"xpack.main.telemetry.telemetryErrorNotificationMessageDescription.tryAgainText": "确认 Kibana 和 Elasticsearch 仍在运行,然后重试。",
"xpack.main.telemetry.telemetryErrorNotificationMessageDescription.unableToSaveTelemetryPreferenceText": "无法保存遥测首选项。",
"xpack.main.telemetry.telemetryErrorNotificationMessageTitle": "遥测错误",
"xpack.main.telemetry.usageDataTitle": "使用情况数据",
"xpack.telemetry.callout.appliesSettingTitle": "此设置适用于{allOfKibanaText}",
"xpack.telemetry.callout.appliesSettingTitle.allOfKibanaText": "所有 Kibana。",
"xpack.telemetry.callout.clusterStatisticsDescription": "这是我们将收集的基本集群统计信息的示例。其包括索引、分片和节点的数目。还包括高级使用情况统计信息,例如监测是否打开。",
"xpack.telemetry.callout.clusterStatisticsTitle": "集群统计信息",
"xpack.telemetry.callout.errorLoadingClusterStatisticsDescription": "尝试提取集群统计信息时发生意外错误。发生此问题的原因可能是 Elasticsearch 出故障、Kibana 出故障,或者有网络错误。检查 Kibana然后重新加载页面并重试。",
"xpack.telemetry.callout.errorLoadingClusterStatisticsTitle": "加载集群统计信息时出错",
"xpack.telemetry.readOurUsageDataPrivacyStatementLinkText": "阅读我们的使用情况数据隐私声明",
"xpack.telemetry.seeExampleOfWhatWeCollectLinkText": "查看我们收集的内容示例",
"xpack.telemetry.telemetryConfigDescription": "通过提供基本功能的使用情况统计信息,来帮助我们改进 Elastic Stack。我们不会在 Elastic 之外共享此数据。",
"xpack.telemetry.telemetryConfigTitle": "遥测选择加入",
"xpack.telemetry.telemetryErrorNotificationMessageDescription.tryAgainText": "确认 Kibana 和 Elasticsearch 仍在运行,然后重试。",
"xpack.telemetry.telemetryErrorNotificationMessageDescription.unableToSaveTelemetryPreferenceText": "无法保存遥测首选项。",
"xpack.telemetry.telemetryErrorNotificationMessageTitle": "遥测错误",
"xpack.telemetry.usageDataTitle": "使用情况数据",
"xpack.main.uiSettings.adminEmailDescription": "X-Pack 管理操作的接收人电子邮件地址,例如来自 Monitoring 的集群告警通知。",
"xpack.main.uiSettings.adminEmailTitle": "管理电子邮件",
"xpack.main.welcomeBanner.licenseIsExpiredDescription": "联系您的管理员或直接{updateYourLicenseLinkText}。",
"xpack.main.welcomeBanner.licenseIsExpiredDescription.updateYourLicenseLinkText": "更新您的许可",
"xpack.main.welcomeBanner.licenseIsExpiredTitle": "您的{licenseType}许可已过期",
"xpack.main.welcomeBanner.noButtonLabel": "否",
"xpack.main.welcomeBanner.telemetryConfigDescription.readMoreLinkText": "阅读更多内容",
"xpack.main.welcomeBanner.telemetryConfigDetailsDescription": "不会发送有关您处理或存储的数据的信息。此功能将定期发送基本功能使用情况统计信息。请参阅{exampleLink}或阅读我们的{telemetryPrivacyStatementLink}。您可以随时禁用此功能。",
"xpack.main.welcomeBanner.telemetryConfigDetailsDescription.exampleLinkText": "示例",
"xpack.main.welcomeBanner.telemetryConfigDetailsDescription.telemetryPrivacyStatementLinkText": "遥测隐私声明",
"xpack.main.welcomeBanner.yesButtonLabel": "是",
"xpack.telemetry.welcomeBanner.noButtonLabel": "否",
"xpack.telemetry.welcomeBanner.telemetryConfigDescription.readMoreLinkText": "阅读更多内容",
"xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription": "不会发送有关您处理或存储的数据的信息。此功能将定期发送基本功能使用情况统计信息。请参阅{exampleLink}或阅读我们的{telemetryPrivacyStatementLink}。您可以随时禁用此功能。",
"xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription.exampleLinkText": "示例",
"xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription.telemetryPrivacyStatementLinkText": "遥测隐私声明",
"xpack.telemetry.welcomeBanner.yesButtonLabel": "是",
"xpack.ml.accessDenied.backToKibanaHomeButtonLabel": "返回 Kibana 主页",
"xpack.ml.accessDenied.noGrantedPrivilegesDescription": "您必须具有 {kibanaUserParam} 和 {machineLearningUserParam} 角色授予的权限。{br}您的系统管理员可以在“管理用户”页面上设置这些角色。",
"xpack.ml.accessDenied.noPermissionToAccessMLLabel": "您需要具备访问 Machine Learning 的权限",

View file

@ -13,34 +13,26 @@ import {
import { mirrorPluginStatus } from '../../server/lib/mirror_plugin_status';
import { replaceInjectedVars } from './server/lib/replace_injected_vars';
import { setupXPackMain } from './server/lib/setup_xpack_main';
import { getLocalizationUsageCollector } from './server/lib/get_localization_usage_collector';
import { createTelemetryUsageCollector } from './server/lib/telemetry';
import { uiCapabilitiesForFeatures } from './server/lib/ui_capabilities_for_features';
import {
xpackInfoRoute,
featuresRoute,
settingsRoute,
} from './server/routes/api/v1';
import { telemetryRoute } from './server/routes/api/v2';
import {
CONFIG_TELEMETRY,
getConfigTelemetryDesc,
} from './common/constants';
import mappings from './mappings.json';
import { i18n } from '@kbn/i18n';
export { callClusterFactory } from './server/lib/call_cluster_factory';
import { registerOssFeatures } from './server/lib/register_oss_features';
import { uiCapabilitiesForFeatures } from './server/lib/ui_capabilities_for_features';
import { has } from 'lodash';
/**
* Determine if Telemetry is enabled.
*
* @param {Object} config Kibana configuration object.
*/
function isTelemetryEnabled(config) {
return config.get('xpack.xpack_main.telemetry.enabled');
function movedToTelemetry(configPath) {
return (settings, log) => {
if (has(settings, configPath)) {
log(`Config key ${configPath} is deprecated. Use "xpack.telemetry.${configPath}" instead.`);
}
};
}
export { callClusterFactory } from './server/lib/call_cluster_factory';
export const xpackMain = (kibana) => {
return new kibana.Plugin({
id: 'xpack_main',
@ -52,15 +44,10 @@ export const xpackMain = (kibana) => {
return Joi.object({
enabled: Joi.boolean().default(true),
telemetry: Joi.object({
// `config` is used internally and not intended to be set
config: Joi.string().default(Joi.ref('$defaultConfigPath')),
enabled: Joi.boolean().default(true),
url: Joi.when('$dev', {
is: true,
then: Joi.string().default('https://telemetry-staging.elastic.co/xpack/v2/send'),
otherwise: Joi.string().default('https://telemetry.elastic.co/xpack/v2/send')
}),
}).default(),
config: Joi.string().default(),
enabled: Joi.boolean().default(),
url: Joi.string().default(),
}).default(), // deprecated
xpack_api_polling_frequency_millis: Joi.number().default(XPACK_INFO_API_DEFAULT_POLL_FREQUENCY_IN_MILLIS),
}).default();
},
@ -70,16 +57,7 @@ export const xpackMain = (kibana) => {
},
uiExports: {
managementSections: ['plugins/xpack_main/views/management'],
uiSettingDefaults: {
[CONFIG_TELEMETRY]: {
name: i18n.translate('xpack.main.telemetry.telemetryConfigTitle', {
defaultMessage: 'Telemetry opt-in'
}),
description: getConfigTelemetryDesc(),
value: false,
readonly: true,
},
[XPACK_DEFAULT_ADMIN_EMAIL_UI_SETTING]: {
name: i18n.translate('xpack.main.uiSettings.adminEmailTitle', {
defaultMessage: 'Admin email'
@ -93,26 +71,8 @@ export const xpackMain = (kibana) => {
value: null
}
},
savedObjectSchemas: {
telemetry: {
isNamespaceAgnostic: true,
},
},
injectDefaultVars(server) {
const config = server.config();
return {
telemetryUrl: config.get('xpack.xpack_main.telemetry.url'),
telemetryEnabled: isTelemetryEnabled(config),
telemetryOptedIn: null,
activeSpace: null,
spacesEnabled: config.get('xpack.spaces.enabled'),
};
},
hacks: [
'plugins/xpack_main/hacks/check_xpack_info_change',
'plugins/xpack_main/hacks/telemetry_opt_in',
'plugins/xpack_main/hacks/telemetry_trigger',
],
replaceInjectedVars,
__webpackPluginProvider__(webpack) {
@ -124,7 +84,6 @@ export const xpackMain = (kibana) => {
raw: true,
});
},
mappings,
},
init(server) {
@ -136,13 +95,13 @@ export const xpackMain = (kibana) => {
// register routes
xpackInfoRoute(server);
telemetryRoute(server);
settingsRoute(server, this.kbnServer);
featuresRoute(server);
// usage collection
server.usage.collectorSet.register(getLocalizationUsageCollector(server));
server.usage.collectorSet.register(createTelemetryUsageCollector(server));
}
},
deprecations: () => [
movedToTelemetry('telemetry.config'),
movedToTelemetry('telemetry.url'),
movedToTelemetry('telemetry.enabled'),
],
});
};

View file

@ -11,6 +11,3 @@ export { AddLicense } from '../../../license_management/public/sections/license_
* For to link to management
*/
export { BASE_PATH as MANAGEMENT_BASE_PATH } from '../../../license_management/common/constants';
export { TelemetryForm } from './telemetry/telemetry_form';
export { OptInExampleFlyout } from './telemetry/opt_in_details_component';

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { getTelemetryOptIn } from './get_telemetry_opt_in';
import { getTelemetryOptIn } from '../../../telemetry/server';
export async function replaceInjectedVars(originalInjectedVars, request, server) {
const xpackInfo = server.plugins.xpack_main.info;

View file

@ -6,7 +6,6 @@
import { injectXPackInfoSignature } from './inject_xpack_info_signature';
import { XPackInfo } from './xpack_info';
import { REPORT_INTERVAL_MS } from '../../common/constants';
import { FeatureRegistry } from './feature_registry';
/**
@ -23,7 +22,6 @@ export function setupXPackMain(server) {
});
server.expose('info', info);
server.expose('telemetryCollectionInterval', REPORT_INTERVAL_MS);
server.expose('createXPackInfo', (options) => new XPackInfo(server, options));
server.ext('onPreResponse', (request, h) => injectXPackInfoSignature(info, request, h));

View file

@ -1,85 +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 expect from '@kbn/expect';
import sinon from 'sinon';
import { getTelemetry } from '../telemetry';
describe('telemetry', () => {
describe('getTelemetry', () => {
const req = { };
const config = { };
const start = 'start';
const end = 'end';
let _getAllStats;
let _getLocalStats;
beforeEach(() => {
config.get = sinon.stub();
_getAllStats = sinon.stub();
_getLocalStats = sinon.stub();
});
it('returns monitoring telemetry when possible', async () => {
const response = [ { totally: 'real' } ];
config.get.withArgs('xpack.monitoring.enabled').returns(true);
_getAllStats.withArgs(req, start, end).returns(response);
expect(await getTelemetry(req, config, start, end, false, { _getAllStats, _getLocalStats })).to.be(response);
expect(config.get.calledOnce).to.be(true);
expect(_getAllStats.calledOnce).to.be(true);
expect(_getLocalStats.calledOnce).to.be(false);
});
it('uses local and ignores monitoring telemetry when empty', async () => {
const response = { collection: 'local' };
config.get.withArgs('xpack.monitoring.enabled').returns(true);
_getAllStats.withArgs(req, start, end).returns([]);
_getLocalStats.withArgs(req).returns(response);
expect(await getTelemetry(req, config, start, end, false, { _getAllStats, _getLocalStats })).to.eql([ response ]);
expect(config.get.calledOnce).to.be(true);
expect(_getAllStats.calledOnce).to.be(true);
expect(_getLocalStats.calledOnce).to.be(true);
});
it('uses local and ignores monitoring telemetry when invalid', async () => {
const response = { collection: 'local' };
config.get.withArgs('xpack.monitoring.enabled').returns(true);
_getAllStats.withArgs(req, start, end).returns({ not: 'an array' });
_getLocalStats.withArgs(req).returns(response);
expect(await getTelemetry(req, config, start, end, false, { _getAllStats, _getLocalStats })).to.eql([ response ]);
expect(config.get.calledOnce).to.be(true);
expect(_getAllStats.calledOnce).to.be(true);
expect(_getLocalStats.calledOnce).to.be(true);
});
it('uses local when monitoring is disabled', async () => {
const response = { collection: 'local' };
config.get.withArgs('xpack.monitoring.enabled').returns(false);
_getLocalStats.withArgs(req).returns(response);
expect(await getTelemetry(req, config, start, end, false, { _getAllStats, _getLocalStats })).to.eql([ response ]);
expect(config.get.calledOnce).to.be(true);
expect(_getAllStats.calledOnce).to.be(false);
expect(_getLocalStats.calledOnce).to.be(true);
});
});
});

View file

@ -1,117 +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 Joi from 'joi';
import { boomify } from 'boom';
import { getAllStats, getLocalStats, encryptTelemetry } from '../../../../lib/telemetry';
/**
* Get the telemetry data.
*
* @param {Object} req The incoming request.
* @param {Object} config Kibana config.
* @param {String} start The start time of the request (likely 20m ago).
* @param {String} end The end time of the request.
* @param {Boolean} unencrypted Is the request payload going to be unencrypted.
* @return {Promise} An array of telemetry objects.
*/
export async function getTelemetry(req, config, start, end, unencrypted, statsGetters = {}) {
const { _getAllStats = getAllStats, _getLocalStats = getLocalStats } = statsGetters;
let response = [];
const useInternalUser = !unencrypted;
if (config.get('xpack.monitoring.enabled')) {
try {
// attempt to collect stats from multiple clusters in monitoring data
response = await _getAllStats(req, start, end, { useInternalUser });
} catch (err) {
// no-op
}
}
if (!Array.isArray(response) || response.length === 0) {
// return it as an array for a consistent API response
response = [await _getLocalStats(req, { useInternalUser })];
}
return response;
}
export function telemetryRoute(server) {
/**
* Change Telemetry Opt-In preference.
*/
server.route({
method: 'POST',
path: '/api/telemetry/v2/optIn',
config: {
validate: {
payload: Joi.object({
enabled: Joi.bool().required()
})
}
},
handler: async (req, h) => {
const savedObjectsClient = req.getSavedObjectsClient();
try {
await savedObjectsClient.create('telemetry', {
enabled: req.payload.enabled
}, {
id: 'telemetry',
overwrite: true,
});
} catch (err) {
return boomify(err);
}
return h.response({}).code(200);
}
});
/**
* Telemetry Data
*
* This provides a mechanism for fetching minor details about all clusters, including details related to the rest of the
* stack (e.g., Kibana).
*/
server.route({
method: 'POST',
path: '/api/telemetry/v2/clusters/_stats',
config: {
validate: {
payload: Joi.object({
unencrypted: Joi.bool(),
timeRange: Joi.object({
min: Joi.date().required(),
max: Joi.date().required()
}).required()
})
}
},
handler: async (req, h) => {
const config = req.server.config();
const start = req.payload.timeRange.min;
const end = req.payload.timeRange.max;
const unencrypted = req.payload.unencrypted;
const isDev = config.get('env.dev');
try {
const usageData = await getTelemetry(req, config, start, end, unencrypted);
if (unencrypted) return usageData;
return encryptTelemetry(usageData, isDev);
} catch (err) {
if (isDev) {
// don't ignore errors when running in dev mode
return boomify(err, { statusCode: err.status });
} else {
const statusCode = unencrypted && err.status === 403 ? 403 : 200;
// ignore errors and return empty set
return h.response([]).code(statusCode);
}
}
}
});
}

View file

@ -12,6 +12,7 @@ export default function ({ loadTestFile }) {
loadTestFile(require.resolve('./security'));
loadTestFile(require.resolve('./monitoring'));
loadTestFile(require.resolve('./xpack_main'));
loadTestFile(require.resolve('./telemetry'));
loadTestFile(require.resolve('./logstash'));
loadTestFile(require.resolve('./kibana'));
loadTestFile(require.resolve('./infra'));

Some files were not shown because too many files have changed in this diff Show more