mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-17 19:13:34 +08:00
feat(@angular-devkit/core): analytics interfaces and basic implementations
This is a preliminary analytics interface. It is meant to be used by every other subsystem where useful, but can be replaced by implementations.
This commit is contained in:
parent
7eb4bab00f
commit
15d7aea2b7
52
packages/angular_devkit/core/src/analytics/api.ts
Normal file
52
packages/angular_devkit/core/src/analytics/api.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
export interface CustomDimensionsAndMetricsOptions {
|
||||||
|
dimensions?: (boolean | number | string)[];
|
||||||
|
metrics?: (boolean | number | string)[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EventOptions extends CustomDimensionsAndMetricsOptions {
|
||||||
|
label?: string;
|
||||||
|
value?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScreenviewOptions extends CustomDimensionsAndMetricsOptions {
|
||||||
|
appVersion?: string;
|
||||||
|
appId?: string;
|
||||||
|
appInstallerId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PageviewOptions extends CustomDimensionsAndMetricsOptions {
|
||||||
|
hostname?: string;
|
||||||
|
title?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimingOptions extends CustomDimensionsAndMetricsOptions {
|
||||||
|
label?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for managing analytics. This is highly platform dependent, and mostly matches
|
||||||
|
* Google Analytics. The reason the interface is here is to remove the dependency to an
|
||||||
|
* implementation from most other places.
|
||||||
|
*
|
||||||
|
* The methods exported from this interface more or less match those needed by us in the
|
||||||
|
* universal analytics package, see https://unpkg.com/@types/universal-analytics@0.4.2/index.d.ts
|
||||||
|
* for typings. We mostly named arguments to make it easier to follow, but didn't change or
|
||||||
|
* add any semantics to those methods. They're mapping GA and u-a one for one.
|
||||||
|
*
|
||||||
|
* The Angular CLI (or any other kind of backend) should forward it to some compatible backend.
|
||||||
|
*/
|
||||||
|
export interface Analytics {
|
||||||
|
event(category: string, action: string, options?: EventOptions): void;
|
||||||
|
screenview(screenName: string, appName: string, options?: ScreenviewOptions): void;
|
||||||
|
pageview(path: string, options?: PageviewOptions): void;
|
||||||
|
timing(category: string, variable: string, time: string | number, options?: TimingOptions): void;
|
||||||
|
|
||||||
|
flush(): Promise<void>;
|
||||||
|
}
|
131
packages/angular_devkit/core/src/analytics/forwarder.ts
Normal file
131
packages/angular_devkit/core/src/analytics/forwarder.ts
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
import { JsonObject } from '../json';
|
||||||
|
import { Analytics, EventOptions, PageviewOptions, ScreenviewOptions, TimingOptions } from './api';
|
||||||
|
|
||||||
|
|
||||||
|
export enum AnalyticsReportKind {
|
||||||
|
Event = 'event',
|
||||||
|
Screenview = 'screenview',
|
||||||
|
Pageview = 'pageview',
|
||||||
|
Timing = 'timing',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AnalyticsReportBase extends JsonObject {
|
||||||
|
kind: AnalyticsReportKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AnalyticsReportEvent extends AnalyticsReportBase {
|
||||||
|
kind: AnalyticsReportKind.Event;
|
||||||
|
options: JsonObject & EventOptions;
|
||||||
|
category: string;
|
||||||
|
action: string;
|
||||||
|
}
|
||||||
|
export interface AnalyticsReportScreenview extends AnalyticsReportBase {
|
||||||
|
kind: AnalyticsReportKind.Screenview;
|
||||||
|
options: JsonObject & ScreenviewOptions;
|
||||||
|
screenName: string;
|
||||||
|
appName: string;
|
||||||
|
}
|
||||||
|
export interface AnalyticsReportPageview extends AnalyticsReportBase {
|
||||||
|
kind: AnalyticsReportKind.Pageview;
|
||||||
|
options: JsonObject & PageviewOptions;
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
export interface AnalyticsReportTiming extends AnalyticsReportBase {
|
||||||
|
kind: AnalyticsReportKind.Timing;
|
||||||
|
options: JsonObject & TimingOptions;
|
||||||
|
category: string;
|
||||||
|
variable: string;
|
||||||
|
time: string | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AnalyticsReport =
|
||||||
|
AnalyticsReportEvent
|
||||||
|
| AnalyticsReportScreenview
|
||||||
|
| AnalyticsReportPageview
|
||||||
|
| AnalyticsReportTiming
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function that can forward analytics along some stream. AnalyticsReport is already a
|
||||||
|
* JsonObject descendant, but we force it here so the user knows it's safe to serialize.
|
||||||
|
*/
|
||||||
|
export type AnalyticsForwarderFn = (report: JsonObject & AnalyticsReport) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that follows the Analytics interface and forwards analytic reports (JavaScript objects).
|
||||||
|
* AnalyticsReporter is the counterpart which takes analytic reports and report them to another
|
||||||
|
* Analytics interface.
|
||||||
|
*/
|
||||||
|
export class ForwardingAnalytics implements Analytics {
|
||||||
|
constructor(protected _fn: AnalyticsForwarderFn) {}
|
||||||
|
|
||||||
|
event(category: string, action: string, options?: EventOptions) {
|
||||||
|
this._fn({
|
||||||
|
kind: AnalyticsReportKind.Event,
|
||||||
|
category,
|
||||||
|
action,
|
||||||
|
options: { ...options } as JsonObject,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
screenview(screenName: string, appName: string, options?: ScreenviewOptions) {
|
||||||
|
this._fn({
|
||||||
|
kind: AnalyticsReportKind.Screenview,
|
||||||
|
screenName,
|
||||||
|
appName,
|
||||||
|
options: { ...options } as JsonObject,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
pageview(path: string, options?: PageviewOptions) {
|
||||||
|
this._fn({
|
||||||
|
kind: AnalyticsReportKind.Pageview,
|
||||||
|
path,
|
||||||
|
options: { ...options } as JsonObject,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
timing(category: string, variable: string, time: string | number, options?: TimingOptions): void {
|
||||||
|
this._fn({
|
||||||
|
kind: AnalyticsReportKind.Timing,
|
||||||
|
category,
|
||||||
|
variable,
|
||||||
|
time,
|
||||||
|
options: { ...options } as JsonObject,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// We do not support flushing.
|
||||||
|
flush() {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class AnalyticsReporter {
|
||||||
|
constructor(protected _analytics: Analytics) {}
|
||||||
|
|
||||||
|
report(report: AnalyticsReport) {
|
||||||
|
switch (report.kind) {
|
||||||
|
case AnalyticsReportKind.Event:
|
||||||
|
this._analytics.event(report.category, report.action, report.options);
|
||||||
|
break;
|
||||||
|
case AnalyticsReportKind.Screenview:
|
||||||
|
this._analytics.screenview(report.screenName, report.appName, report.options);
|
||||||
|
break;
|
||||||
|
case AnalyticsReportKind.Pageview:
|
||||||
|
this._analytics.pageview(report.path, report.options);
|
||||||
|
break;
|
||||||
|
case AnalyticsReportKind.Timing:
|
||||||
|
this._analytics.timing(report.category, report.variable, report.time, report.options);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error('Unexpected analytics report: ' + JSON.stringify(report));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
packages/angular_devkit/core/src/analytics/index.ts
Normal file
12
packages/angular_devkit/core/src/analytics/index.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
export * from './api';
|
||||||
|
export * from './forwarder';
|
||||||
|
export * from './logging';
|
||||||
|
export * from './multi';
|
||||||
|
export * from './noop';
|
34
packages/angular_devkit/core/src/analytics/logging.ts
Normal file
34
packages/angular_devkit/core/src/analytics/logging.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
import { Logger } from '../logger';
|
||||||
|
import { Analytics, EventOptions, PageviewOptions, ScreenviewOptions, TimingOptions } from './api';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analytics implementation that logs analytics events to a logger. This should be used for
|
||||||
|
* debugging mainly.
|
||||||
|
*/
|
||||||
|
export class LoggingAnalytics implements Analytics {
|
||||||
|
constructor(protected _logger: Logger) {}
|
||||||
|
|
||||||
|
event(category: string, action: string, options?: EventOptions): void {
|
||||||
|
this._logger.info('event ' + JSON.stringify({ category, action, ...options }));
|
||||||
|
}
|
||||||
|
screenview(screenName: string, appName: string, options?: ScreenviewOptions): void {
|
||||||
|
this._logger.info('screenview ' + JSON.stringify({ screenName, appName, ...options }));
|
||||||
|
}
|
||||||
|
pageview(path: string, options?: PageviewOptions): void {
|
||||||
|
this._logger.info('pageview ' + JSON.stringify({ path, ...options }));
|
||||||
|
}
|
||||||
|
timing(category: string, variable: string, time: string | number, options?: TimingOptions): void {
|
||||||
|
this._logger.info('timing ' + JSON.stringify({ category, variable, time, ...options }));
|
||||||
|
}
|
||||||
|
|
||||||
|
flush(): Promise<void> {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
38
packages/angular_devkit/core/src/analytics/multi.ts
Normal file
38
packages/angular_devkit/core/src/analytics/multi.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Analytics, EventOptions, PageviewOptions, ScreenviewOptions, TimingOptions } from './api';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analytics implementation that reports to multiple analytics backend.
|
||||||
|
*/
|
||||||
|
export class MultiAnalytics implements Analytics {
|
||||||
|
constructor(protected _backends: Analytics[] = []) {}
|
||||||
|
|
||||||
|
push(...backend: Analytics[]) {
|
||||||
|
this._backends.push(...backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
event(category: string, action: string, options?: EventOptions): void {
|
||||||
|
this._backends.forEach(be => be.event(category, action, options));
|
||||||
|
}
|
||||||
|
screenview(screenName: string, appName: string, options?: ScreenviewOptions): void {
|
||||||
|
this._backends.forEach(be => be.screenview(screenName, appName, options));
|
||||||
|
}
|
||||||
|
pageview(path: string, options?: PageviewOptions): void {
|
||||||
|
this._backends.forEach(be => be.pageview(path, options));
|
||||||
|
}
|
||||||
|
timing(category: string, variable: string, time: string | number, options?: TimingOptions): void {
|
||||||
|
this._backends.forEach(be => be.timing(category, variable, time, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
flush(): Promise<void> {
|
||||||
|
return Promise.all(this._backends.map(x => x.flush())).then(() => {});
|
||||||
|
}
|
||||||
|
}
|
19
packages/angular_devkit/core/src/analytics/noop.ts
Normal file
19
packages/angular_devkit/core/src/analytics/noop.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
import { Analytics } from './api';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analytics implementation that does nothing.
|
||||||
|
*/
|
||||||
|
export class NoopAnalytics implements Analytics {
|
||||||
|
event() {}
|
||||||
|
screenview() {}
|
||||||
|
pageview() {}
|
||||||
|
timing() {}
|
||||||
|
flush(): Promise<void> { return Promise.resolve(); }
|
||||||
|
}
|
@ -5,6 +5,7 @@
|
|||||||
* Use of this source code is governed by an MIT-style license that can be
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
import * as analytics from './analytics';
|
||||||
import * as experimental from './experimental';
|
import * as experimental from './experimental';
|
||||||
import * as json from './json/index';
|
import * as json from './json/index';
|
||||||
import * as logging from './logger/index';
|
import * as logging from './logger/index';
|
||||||
@ -16,6 +17,7 @@ export * from './utils/index';
|
|||||||
export * from './virtual-fs/index';
|
export * from './virtual-fs/index';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
analytics,
|
||||||
experimental,
|
experimental,
|
||||||
json,
|
json,
|
||||||
logging,
|
logging,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user