Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Telemetry] Server side fetcher #50015

Merged
merged 64 commits into from
Nov 13, 2019
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
4860e53
initial push
Bamieh Nov 4, 2019
d7f7f60
self code review
Bamieh Nov 4, 2019
27d6b67
ignore node-fetch type
Bamieh Nov 4, 2019
0037d75
usageFetcher api
Bamieh Nov 4, 2019
4436f3f
user agent metric
Bamieh Nov 6, 2019
2715b43
merge master + add tests
Bamieh Nov 6, 2019
e0c10b6
Merge branch 'master' of github.com:elastic/kibana into telemetry/ser…
Bamieh Nov 6, 2019
0815769
telemetry plugin collector
Bamieh Nov 6, 2019
df1f45f
remove extra unused method
Bamieh Nov 6, 2019
dae375a
remove unused import
Bamieh Nov 6, 2019
01cfc26
type check
Bamieh Nov 6, 2019
b58d029
fix collections tests
Bamieh Nov 6, 2019
16c8e1d
pass kfetch as dep
Bamieh Nov 6, 2019
78d4d88
Merge branch 'master' of github.com:elastic/kibana into telemetry/ser…
Bamieh Nov 6, 2019
873640f
add ui metrics integration test for user agent
Bamieh Nov 7, 2019
5fcd303
Merge branch 'master' of github.com:elastic/kibana into telemetry/ser…
Bamieh Nov 7, 2019
c1926ac
dont start ui metrics when not authenticated
Bamieh Nov 7, 2019
5a62e7d
user agent count always 1
Bamieh Nov 7, 2019
64056ea
fix broken ui-metric integration tests
Bamieh Nov 7, 2019
e51c642
try using config.get
Bamieh Nov 7, 2019
f648bb9
avoid fetching configs if sending
Bamieh Nov 7, 2019
e394a78
type unknown -> string
Bamieh Nov 7, 2019
5818d94
check if fetcher is causing the issue
Bamieh Nov 7, 2019
120b832
disable ui_metric from functional tests
Bamieh Nov 7, 2019
c757cb5
enable ui_metric back again
Bamieh Nov 7, 2019
087ad8e
ignore keyword above 256
Bamieh Nov 7, 2019
076b06c
check requesting app first
Bamieh Nov 7, 2019
b954daa
clean up after all the debugging :)
Bamieh Nov 7, 2019
e5967de
fix tests
Bamieh Nov 7, 2019
7f7b7cc
always return 200 for ui metric reporting
Bamieh Nov 7, 2019
4cb7da9
remove boom import
Bamieh Nov 7, 2019
f8ab109
logout after removing role/user
Bamieh Nov 7, 2019
0db44f2
Merge branch 'master' of github.com:elastic/kibana into telemetry/ser…
Bamieh Nov 7, 2019
993fcd7
undo some changes in tests
Bamieh Nov 7, 2019
88c8fae
inside try catch
Bamieh Nov 8, 2019
8b0692f
prevent potential race conditions in priorities with =
Bamieh Nov 8, 2019
9a0740c
Merge branch 'master' of github.com:elastic/kibana into telemetry/ser…
Bamieh Nov 8, 2019
612252a
Merge branch 'master' of github.com:elastic/kibana into telemetry/ser…
Bamieh Nov 11, 2019
176ac34
use snake_case for telemetry plugin collection
Bamieh Nov 11, 2019
c72efcf
Merge branch 'master' into telemetry/server_fetcher
elasticmachine Nov 11, 2019
b768d19
Merge branch 'master' into telemetry/server_fetcher
elasticmachine Nov 11, 2019
f34101e
merge master + work on code review feedback + allowChangingOptInStatu…
Bamieh Nov 12, 2019
bb1e6d5
Merge branch 'telemetry/server_fetcher' of github.com:Bamieh/kibana i…
Bamieh Nov 12, 2019
495fc81
usageFetcher -> sendUsageFrom
Bamieh Nov 12, 2019
832841a
more replacements
Bamieh Nov 12, 2019
3956c1f
remove extra unused route
Bamieh Nov 12, 2019
925c3e4
config() -> config
Bamieh Nov 12, 2019
703f1f3
Update src/legacy/core_plugins/telemetry/index.ts
Bamieh Nov 12, 2019
ec4dabf
Update src/legacy/core_plugins/ui_metric/server/routes/api/ui_metric.ts
Bamieh Nov 12, 2019
17e4318
config() -> config
Bamieh Nov 12, 2019
2c1aff7
Merge branch 'telemetry/server_fetcher' of github.com:Bamieh/kibana i…
Bamieh Nov 12, 2019
29a6a67
fix SO update logic given the current changes
Bamieh Nov 12, 2019
944599a
fix opt in check
Bamieh Nov 12, 2019
4527308
triple check
Bamieh Nov 12, 2019
62f65ea
check for non boolean
Bamieh Nov 12, 2019
c70becc
Merge branch 'master' of github.com:elastic/kibana into telemetry/ser…
Bamieh Nov 12, 2019
73bcafd
Merge branch 'master' into telemetry/server_fetcher
elasticmachine Nov 12, 2019
cd0730e
take into account older settings
Bamieh Nov 12, 2019
1fbcd73
Merge branch 'telemetry/server_fetcher' of github.com:Bamieh/kibana i…
Bamieh Nov 12, 2019
88f1b73
import TelemetryOptInProvider
Bamieh Nov 12, 2019
3961073
Merge branch 'master' into telemetry/server_fetcher
elasticmachine Nov 12, 2019
2c12688
update test case
Bamieh Nov 13, 2019
d88e765
Merge branch 'telemetry/server_fetcher' of github.com:Bamieh/kibana i…
Bamieh Nov 13, 2019
6a077d3
Merge branch 'master' of github.com:elastic/kibana into telemetry/ser…
Bamieh Nov 13, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/kbn-analytics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
"@babel/cli": "7.5.5",
"@kbn/dev-utils": "1.0.0",
"@kbn/babel-preset": "1.0.0",
"typescript": "3.5.1"
"typescript": "3.5.3"
}
}
2 changes: 1 addition & 1 deletion packages/kbn-analytics/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
* under the License.
*/

export { createReporter, ReportHTTP, Reporter, ReporterConfig } from './reporter';
export { ReportHTTP, Reporter, ReporterConfig } from './reporter';
export { UiStatsMetricType, METRIC_TYPE } from './metrics';
export { Report, ReportManager } from './report';
16 changes: 6 additions & 10 deletions packages/kbn-analytics/src/metrics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,17 @@
* under the License.
*/

import { UiStatsMetric, UiStatsMetricType } from './ui_stats';
import { UiStatsMetric } from './ui_stats';
import { UserAgentMetric } from './user_agent';

export {
UiStatsMetric,
createUiStatsMetric,
UiStatsMetricReport,
UiStatsMetricType,
} from './ui_stats';
export { UiStatsMetric, createUiStatsMetric, UiStatsMetricType } from './ui_stats';
export { Stats } from './stats';
export { trackUsageAgent } from './user_agent';

export type Metric = UiStatsMetric<UiStatsMetricType>;
export type MetricType = keyof typeof METRIC_TYPE;

export type Metric = UiStatsMetric | UserAgentMetric;
export enum METRIC_TYPE {
COUNT = 'count',
LOADED = 'loaded',
CLICK = 'click',
USER_AGENT = 'user_agent',
}
28 changes: 12 additions & 16 deletions packages/kbn-analytics/src/metrics/ui_stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,33 @@
* under the License.
*/

import { Stats } from './stats';
import { METRIC_TYPE } from './';

export type UiStatsMetricType = METRIC_TYPE.CLICK | METRIC_TYPE.LOADED | METRIC_TYPE.COUNT;
export interface UiStatsMetricConfig<T extends UiStatsMetricType> {
type: T;
export interface UiStatsMetricConfig {
type: UiStatsMetricType;
appName: string;
eventName: string;
count?: number;
}

export interface UiStatsMetric<T extends UiStatsMetricType = UiStatsMetricType> {
type: T;
export interface UiStatsMetric {
type: UiStatsMetricType;
appName: string;
eventName: string;
count: number;
}

export function createUiStatsMetric<T extends UiStatsMetricType>({
export function createUiStatsMetric({
type,
appName,
eventName,
count = 1,
}: UiStatsMetricConfig<T>): UiStatsMetric<T> {
return { type, appName, eventName, count };
}

export interface UiStatsMetricReport {
key: string;
appName: string;
eventName: string;
type: UiStatsMetricType;
stats: Stats;
}: UiStatsMetricConfig): UiStatsMetric {
return {
type,
appName,
eventName,
count,
};
}
35 changes: 35 additions & 0 deletions packages/kbn-analytics/src/metrics/user_agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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 { METRIC_TYPE } from './';

export interface UserAgentMetric {
type: METRIC_TYPE.USER_AGENT;
appName: string;
userAgent: string;
}

export function trackUsageAgent(appName: string): UserAgentMetric {
const userAgent =
window && window.navigator && window.navigator.userAgent ? window.navigator.userAgent : '';
Bamieh marked this conversation as resolved.
Show resolved Hide resolved
return {
type: METRIC_TYPE.USER_AGENT,
appName,
userAgent,
};
}
61 changes: 49 additions & 12 deletions packages/kbn-analytics/src/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,47 @@
* under the License.
*/

import { UnreachableCaseError } from './util';
import { Metric, Stats, UiStatsMetricReport, METRIC_TYPE } from './metrics';
import { UnreachableCaseError, wrapArray } from './util';
import { Metric, Stats, UiStatsMetricType, METRIC_TYPE } from './metrics';
const REPORT_VERSION = 1;

export interface Report {
reportVersion: typeof REPORT_VERSION;
uiStatsMetrics: {
[key: string]: UiStatsMetricReport;
[key: string]: {
key: string;
appName: string;
eventName: string;
type: UiStatsMetricType;
stats: Stats;
};
};
userAgent?: {
[key: string]: {
userAgent: string;
key: string;
type: METRIC_TYPE.USER_AGENT;
appName: string;
};
};
}

export class ReportManager {
static REPORT_VERSION = REPORT_VERSION;
public report: Report;
constructor(report?: Report) {
this.report = report || ReportManager.createReport();
}
static createReport() {
return { uiStatsMetrics: {} };
static createReport(): Report {
return { reportVersion: REPORT_VERSION, uiStatsMetrics: {} };
}
public clearReport() {
this.report = ReportManager.createReport();
}
public isReportEmpty(): boolean {
return Object.keys(this.report.uiStatsMetrics).length === 0;
const noUiStats = Object.keys(this.report.uiStatsMetrics).length === 0;
const noUserAgent = !this.report.userAgent || Object.keys(this.report.userAgent).length === 0;
return noUiStats && noUserAgent;
}
private incrementStats(count: number, stats?: Stats): Stats {
const { min = 0, max = 0, sum = 0 } = stats || {};
Expand All @@ -54,28 +73,46 @@ export class ReportManager {
sum: newSum,
};
}
assignReports(newMetrics: Metric[]) {
newMetrics.forEach(newMetric => this.assignReport(this.report, newMetric));
assignReports(newMetrics: Metric | Metric[]) {
wrapArray(newMetrics).forEach(newMetric => this.assignReport(this.report, newMetric));
}
static createMetricKey(metric: Metric): string {
switch (metric.type) {
case METRIC_TYPE.USER_AGENT: {
const { appName, type } = metric;
return `${appName}-${type}`;
}
case METRIC_TYPE.CLICK:
case METRIC_TYPE.LOADED:
case METRIC_TYPE.COUNT: {
const { appName, type, eventName } = metric;
const { appName, eventName, type } = metric;
return `${appName}-${type}-${eventName}`;
}
default:
throw new UnreachableCaseError(metric.type);
throw new UnreachableCaseError(metric);
}
}
private assignReport(report: Report, metric: Metric) {
const key = ReportManager.createMetricKey(metric);
switch (metric.type) {
case METRIC_TYPE.USER_AGENT: {
const { appName, type, userAgent } = metric;
if (userAgent) {
this.report.userAgent = {
[key]: {
key,
appName,
type,
userAgent: metric.userAgent,
},
};
}
return;
}
case METRIC_TYPE.CLICK:
case METRIC_TYPE.LOADED:
case METRIC_TYPE.COUNT: {
const { appName, type, eventName, count } = metric;
const key = ReportManager.createMetricKey(metric);
const existingStats = (report.uiStatsMetrics[key] || {}).stats;
this.report.uiStatsMetrics[key] = {
key,
Expand All @@ -87,7 +124,7 @@ export class ReportManager {
return;
}
default:
throw new UnreachableCaseError(metric.type);
throw new UnreachableCaseError(metric);
}
}
}
46 changes: 28 additions & 18 deletions packages/kbn-analytics/src/reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/

import { wrapArray } from './util';
import { Metric, UiStatsMetric, createUiStatsMetric } from './metrics';
import { Metric, createUiStatsMetric, trackUsageAgent, UiStatsMetricType } from './metrics';

import { Storage, ReportStorageManager } from './storage';
import { Report, ReportManager } from './report';
Expand All @@ -40,10 +40,11 @@ export class Reporter {
private reportManager: ReportManager;
private storageManager: ReportStorageManager;
private debug: boolean;
private retryCount = 0;
private readonly maxRetries = 3;

constructor(config: ReporterConfig) {
const { http, storage, debug, checkInterval = 10000, storageKey = 'analytics' } = config;

const { http, storage, debug, checkInterval = 90000, storageKey = 'analytics' } = config;
this.http = http;
this.checkInterval = checkInterval;
this.interval = null;
Expand All @@ -63,14 +64,14 @@ export class Reporter {
this.storageManager.store(this.reportManager.report);
}

public start() {
public start = () => {
Bamieh marked this conversation as resolved.
Show resolved Hide resolved
if (!this.interval) {
this.interval = setTimeout(() => {
this.interval = null;
this.sendReports();
}, this.checkInterval);
}
}
};
Bamieh marked this conversation as resolved.
Show resolved Hide resolved

private log(message: any) {
if (this.debug) {
Expand All @@ -79,36 +80,45 @@ export class Reporter {
}
}

public reportUiStats(
public reportUiStats = (
appName: string,
type: UiStatsMetric['type'],
type: UiStatsMetricType,
eventNames: string | string[],
count?: number
) {
) => {
const metrics = wrapArray(eventNames).map(eventName => {
if (this) this.log(`${type} Metric -> (${appName}:${eventName}):`);
this.log(`${type} Metric -> (${appName}:${eventName}):`);
const report = createUiStatsMetric({ type, appName, eventName, count });
this.log(report);
return report;
});
this.saveToReport(metrics);
}
};

public reportUserAgent = (appName: string) => {
this.log(`Reporting user-agent.`);
const report = trackUsageAgent(appName);
this.saveToReport([report]);
};

public async sendReports() {
public sendReports = async () => {
if (!this.reportManager.isReportEmpty()) {
try {
await this.http(this.reportManager.report);
this.flushReport();
this.retryCount = 0;
} catch (err) {
this.retryCount = this.retryCount + 1;
this.log(`Error Sending Metrics Report ${err}`);
if (this.retryCount > this.maxRetries) {
this.log(`Max retries reached; Flushing report.`);
this.flushReport();
} else if (this.reportManager.report.reportVersion !== ReportManager.REPORT_VERSION) {
Bamieh marked this conversation as resolved.
Show resolved Hide resolved
this.log(`Report Version mismatch; Flushing report.`);
this.flushReport();
Bamieh marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
this.start();
}
}

export function createReporter(reportedConf: ReporterConfig) {
const reporter = new Reporter(reportedConf);
reporter.start();
return reporter;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ kibana_vars=(
xpack.security.secureCookies
xpack.security.sessionTimeout
telemetry.enabled
telemetry.usageFetcher
)

longopts=''
Expand Down
6 changes: 6 additions & 0 deletions src/legacy/core_plugins/telemetry/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ export const PRIVACY_STATEMENT_URL = `https://www.elastic.co/legal/telemetry-pri
*/
export const KIBANA_LOCALIZATION_STATS_TYPE = 'localization';

/**
* The type name used to publish telemetry plugin stats.
* @type {string}
*/
export const TELEMETRY_STATS_TYPE = 'telemetry';

/**
* UI metric usage type
* @type {string}
Expand Down
Loading