Skip to content

Commit 83c63f5

Browse files
committed
feat: add initial preformance tracking
1 parent f4768e0 commit 83c63f5

19 files changed

+194
-31
lines changed

lib/bootstrap.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ $injector.require("nativescript-cli", "./nativescript-cli");
88
$injector.requirePublicClass("constants", "./constants-provider");
99
$injector.require("projectData", "./project-data");
1010
$injector.requirePublic("projectDataService", "./services/project-data-service");
11+
$injector.require("performanceService", "./services/performance-service");
1112
$injector.requirePublic("projectService", "./services/project-service");
1213
$injector.require("androidProjectService", "./services/android-project-service");
1314
$injector.require("androidPluginBuildService", "./services/android-plugin-build-service");

lib/common/decorators.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const { performance } = require('perf_hooks');
2+
13
/**
24
* Caches the result of the first execution of the method and returns it whenever it is called instead of executing it again.
35
* Works with methods and getters.
@@ -83,3 +85,49 @@ export function exported(moduleName: string): any {
8385
return descriptor;
8486
};
8587
}
88+
89+
export function performanceLog(injector?: IInjector): any {
90+
injector = injector || $injector;
91+
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor): any {
92+
const originalMethod = descriptor.value;
93+
const className = target.constructor.name;
94+
const trackName = `${className}.${propertyKey}`;
95+
const performanceService: IPerformanceService = injector.resolve("performanceService");
96+
97+
//needed for the returned function to have the same name as the original - used in hooks decorator
98+
const tempObject = {
99+
[originalMethod.name]: function (...args: Array<any>) {
100+
const start = performance.now();
101+
const result = originalMethod.apply(this, args);
102+
const resolvedPromise = Promise.resolve(result);
103+
let end;
104+
105+
if (resolvedPromise !== result) {
106+
end = performance.now();
107+
performanceService.processExecutionData(trackName, start, end, args);
108+
} else {
109+
resolvedPromise
110+
.then(() => {
111+
end = performance.now();
112+
performanceService.processExecutionData(trackName, start, end, args);
113+
})
114+
.catch((err) => {
115+
end = performance.now();
116+
performanceService.processExecutionData(trackName, start, end, args);
117+
});
118+
119+
}
120+
121+
return result;
122+
}
123+
}
124+
descriptor.value = tempObject[originalMethod.name]
125+
126+
// used to get parameter names in hooks decorator
127+
descriptor.value.toString = () => {
128+
return originalMethod.toString();
129+
};
130+
131+
return descriptor;
132+
};
133+
}

lib/common/definitions/google-analytics.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ interface IEventActionData {
4848
* Project directory, in case the action is executed inside project.
4949
*/
5050
projectDir?: string;
51+
52+
/**
53+
* Value that should be tracked
54+
*/
55+
value?: number;
5156
}
5257

5358
/**

lib/common/helpers.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,33 @@ export function stringify(value: any, replacer?: (key: string, value: any) => an
568568
return JSON.stringify(value, replacer, space || 2);
569569
}
570570

571+
export function getFormattedDate(): string {
572+
const currentDate = new Date();
573+
const year = currentDate.getFullYear();
574+
const month = getFormattedDateComponent((currentDate.getMonth() + 1));
575+
const day = getFormattedDateComponent(currentDate.getDate());
576+
const hour = getFormattedDateComponent(currentDate.getHours());
577+
const minutes = getFormattedDateComponent(currentDate.getMinutes());
578+
const seconds = getFormattedDateComponent(currentDate.getSeconds());
579+
const milliseconds = getFormattedMilliseconds(currentDate);
580+
581+
return `${[year, month, day].join('-')} ${[hour, minutes, seconds].join(":")}.${milliseconds}`;
582+
}
583+
584+
export function getFormattedDateComponent(component: number): string {
585+
const stringComponent = component.toString();
586+
return stringComponent.length === 1 ? `0${stringComponent}` : stringComponent;
587+
}
588+
589+
export function getFormattedMilliseconds(date: Date): string {
590+
let milliseconds = date.getMilliseconds().toString();
591+
while (milliseconds.length < 3) {
592+
milliseconds = `0${milliseconds}`;
593+
}
594+
595+
return milliseconds;
596+
}
597+
571598
//--- begin part copied from AngularJS
572599

573600
//The MIT License

lib/constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ export const enum TrackActionNames {
152152
CheckLocalBuildSetup = "Check Local Build Setup",
153153
CheckEnvironmentRequirements = "Check Environment Requirements",
154154
Options = "Options",
155-
AcceptTracking = "Accept Tracking"
155+
AcceptTracking = "Accept Tracking",
156+
Performance = "Performance"
156157
}
157158

158159
export const AnalyticsEventLabelDelimiter = "__";

lib/declarations.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ interface INodePackageManager {
7575
getCachePath(): Promise<string>;
7676
}
7777

78+
interface IPerformanceService {
79+
processExecutionData(methodInfo: string, startTime: number, endTime: number, args: any[]): void;
80+
}
81+
7882
interface IPackageInstallationManager {
7983
install(packageName: string, packageDir: string, options?: INpmInstallOptions): Promise<any>;
8084
getLatestVersion(packageName: string): Promise<string>;
@@ -563,6 +567,7 @@ interface IOptions extends IRelease, IDeviceIdentifier, IJustLaunch, IAvd, IAvai
563567
hmr: boolean;
564568
link: boolean;
565569
analyticsLogFile: string;
570+
performance: Object;
566571
}
567572

568573
interface IEnvOptions {

lib/options.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ export class Options {
119119
analyticsLogFile: { type: OptionType.String, hasSensitiveValue: true },
120120
hooks: { type: OptionType.Boolean, default: true, hasSensitiveValue: false },
121121
link: { type: OptionType.Boolean, default: false, hasSensitiveValue: false },
122-
aab: { type: OptionType.Boolean, hasSensitiveValue: false }
122+
aab: { type: OptionType.Boolean, hasSensitiveValue: false },
123+
performance: { type: OptionType.Object, hasSensitiveValue: true }
123124
};
124125
}
125126

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { EOL } from "os";
2+
import { getFormattedDate } from "../../common/helpers";
23

34
export class AnalyticsLoggingService implements IAnalyticsLoggingService {
45
constructor(private $fs: IFileSystem,
@@ -7,35 +8,8 @@ export class AnalyticsLoggingService implements IAnalyticsLoggingService {
78
public logData(analyticsLoggingMessage: IAnalyticsLoggingMessage): void {
89
if (this.logFile && analyticsLoggingMessage && analyticsLoggingMessage.message) {
910
analyticsLoggingMessage.type = analyticsLoggingMessage.type || AnalyticsLoggingMessageType.Info;
10-
const formattedDate = this.getFormattedDate();
11+
const formattedDate = getFormattedDate();
1112
this.$fs.appendFile(this.logFile, `[${formattedDate}] [${analyticsLoggingMessage.type}] ${analyticsLoggingMessage.message}${EOL}`);
1213
}
1314
}
14-
15-
private getFormattedDate(): string {
16-
const currentDate = new Date();
17-
const year = currentDate.getFullYear();
18-
const month = this.getFormattedDateComponent((currentDate.getMonth() + 1));
19-
const day = this.getFormattedDateComponent(currentDate.getDate());
20-
const hour = this.getFormattedDateComponent(currentDate.getHours());
21-
const minutes = this.getFormattedDateComponent(currentDate.getMinutes());
22-
const seconds = this.getFormattedDateComponent(currentDate.getSeconds());
23-
const milliseconds = this.getFormattedMilliseconds(currentDate);
24-
25-
return `${[year, month, day].join('-')} ${[hour, minutes, seconds].join(":")}.${milliseconds}`;
26-
}
27-
28-
private getFormattedDateComponent(component: number): string {
29-
const stringComponent = component.toString();
30-
return stringComponent.length === 1 ? `0${stringComponent}` : stringComponent;
31-
}
32-
33-
private getFormattedMilliseconds(date: Date): string {
34-
let milliseconds = date.getMilliseconds().toString();
35-
while (milliseconds.length < 3) {
36-
milliseconds = `0${milliseconds}`;
37-
}
38-
39-
return milliseconds;
40-
}
4115
}

lib/services/analytics/analytics-service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ export class AnalyticsService implements IAnalyticsService, IDisposable {
122122
googleAnalyticsDataType: GoogleAnalyticsDataType.Event,
123123
action: data.action,
124124
label,
125-
customDimensions
125+
customDimensions,
126+
value: data.value
126127
};
127128

128129
await this.trackInGoogleAnalytics(googleAnalyticsEventData);

lib/services/android-project-service.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { DeviceAndroidDebugBridge } from "../common/mobile/android/device-androi
77
import { attachAwaitDetach, isRecommendedAarFile } from "../common/helpers";
88
import { Configurations, LiveSyncPaths } from "../common/constants";
99
import { SpawnOptions } from "child_process";
10+
import { performanceLog } from ".././common/decorators";
1011

1112
export class AndroidProjectService extends projectServiceBaseLib.PlatformProjectServiceBase implements IPlatformProjectService {
1213
private static VALUES_DIRNAME = "values";
@@ -325,6 +326,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
325326
return true;
326327
}
327328

329+
@performanceLog()
328330
public async buildProject(projectRoot: string, projectData: IProjectData, buildConfig: IBuildConfig): Promise<void> {
329331
let task;
330332
const gradleArgs = this.getGradleBuildOptions(buildConfig, projectData);

0 commit comments

Comments
 (0)