Browse Source

telemetry manager
and model id

Raanan Weber 7 years ago
parent
commit
6e69fd0d35

+ 1 - 0
Viewer/src/configuration/configuration.ts

@@ -85,6 +85,7 @@ export interface ViewerConfiguration {
 }
 
 export interface IModelConfiguration {
+    id?: string;
     url?: string;
     root?: string; //optional
     loader?: string; // obj, gltf?

+ 3 - 1
Viewer/src/index.ts

@@ -4,6 +4,7 @@ import { viewerGlobals } from './configuration/globals';
 import { viewerManager } from './viewer/viewerManager';
 import { DefaultViewer } from './viewer/defaultViewer';
 import { AbstractViewer } from './viewer/viewer';
+import { telemetryManager } from './telemetryManager';
 import { ModelLoader } from './model/modelLoader';
 import { ViewerModel, ModelState } from './model/viewerModel';
 import { AnimationPlayMode, AnimationState } from './model/modelAnimation';
@@ -35,9 +36,10 @@ let disableInit: boolean = viewerGlobals.disableInit;
 function disposeAll() {
     viewerManager.dispose();
     mapperManager.dispose();
+    telemetryManager.dispose();
 }
 
 const Version = BABYLON.Engine.Version;
 
 // public API for initialization
-export { BABYLON, Version, InitTags, DefaultViewer, AbstractViewer, viewerGlobals, disableInit, viewerManager, mapperManager, disposeAll, ModelLoader, ViewerModel, AnimationPlayMode, AnimationState, ModelState };
+export { BABYLON, Version, InitTags, DefaultViewer, AbstractViewer, viewerGlobals, telemetryManager, disableInit, viewerManager, mapperManager, disposeAll, ModelLoader, ViewerModel, AnimationPlayMode, AnimationState, ModelState };

+ 124 - 0
Viewer/src/telemetryManager.ts

@@ -0,0 +1,124 @@
+import { Engine, Observable } from "babylonjs";
+import { AbstractViewer } from "./viewer/viewer";
+
+/**
+ * The data structure of a telemetry event.
+ */
+export interface TelemetryData {
+    event: string;
+    session: string;
+    date: Date;
+    now: number;
+    viewer?: AbstractViewer
+    detail: any;
+}
+
+/**
+ * Receives Telemetry events and raises events to the API
+ */
+export class TelemetryManager {
+
+    public onEventBroadcastedObservable: Observable<TelemetryData> = new Observable();
+
+    private _currentSessionId: string;
+
+    private _event: (event: string, viewer: AbstractViewer, details?: any) => void = this._eventEnabled;
+
+    /**
+     * Receives a telemetry event
+     * @param event The name of the Telemetry event
+     * @param details An additional value, or an object containing a list of property/value pairs
+     */
+    public get broadcast() {
+        return this._event;
+    }
+
+    /**
+     * Log a Telemetry event for errors raised on the WebGL context.
+     * @param engine The Babylon engine with the WebGL context.
+     */
+    public flushWebGLErrors(viewer: AbstractViewer) {
+        const engine = viewer.engine;
+        if (!engine) {
+            return;
+        }
+        let logErrors = true;
+
+        while (logErrors) {
+            let gl = (<any>engine)._gl;
+            let error = gl.getError();
+            if (error === gl.NO_ERROR) {
+                logErrors = false;
+            } else {
+                this.broadcast("WebGL Error", viewer, { error: error });
+            }
+        }
+    }
+
+    /**
+     * Enable or disable telemetry events
+     * @param enabled Boolan, true if events are enabled 
+     */
+    public set enable(enabled: boolean) {
+        if (enabled) {
+            this._event = this._eventEnabled;
+        } else {
+            this._event = this._eventDisabled;
+        }
+    }
+
+    /**
+     * Called on event when disabled, typically do nothing here
+     */
+    private _eventDisabled(): void {
+        // nothing to do
+    }
+
+    /**
+     * Called on event when enabled
+     * @param event - The name of the Telemetry event
+     * @param details An additional value, or an object containing a list of property/value pairs
+     */
+    private _eventEnabled(event: string, viewer?: AbstractViewer, details?: any): void {
+        let telemetryData: TelemetryData = {
+            viewer,
+            event: event,
+            session: this.session,
+            date: new Date(),
+            now: window.performance ? window.performance.now() : Date.now(),
+            detail: null
+        };
+
+        if (typeof details === "object") {
+            for (var attr in details) {
+                if (details.hasOwnProperty(attr)) {
+                    telemetryData[attr] = details[attr];
+                }
+            }
+        } else if (details) {
+            telemetryData.detail = details;
+        }
+
+        this.onEventBroadcastedObservable.notifyObservers(telemetryData);
+    }
+
+    /**
+     * Returns the current session ID or creates one if it doesn't exixt
+     * @return The current session ID
+     */
+    public get session(): string {
+        if (!this._currentSessionId) {
+            //String + Timestamp + Random Integer
+            this._currentSessionId = "SESSION_" + Date.now() + Math.floor(Math.random() * 0x10000);
+        }
+        return this._currentSessionId;
+    }
+
+    public dispose() {
+        this.onEventBroadcastedObservable.clear();
+        delete this.onEventBroadcastedObservable;
+    }
+}
+
+export const telemetryManager = new TelemetryManager();
+

+ 8 - 0
Viewer/src/viewer/sceneManager.ts

@@ -786,6 +786,14 @@ export class SceneManager {
      */
     public dispose() {
 
+        // this.onCameraConfiguredObservable.clear();
+        this.onEnvironmentConfiguredObservable.clear();
+        this.onLightsConfiguredObservable.clear();
+        this.onModelsConfiguredObservable.clear();
+        this.onSceneConfiguredObservable.clear();
+        this.onSceneInitObservable.clear();
+        this.onSceneOptimizerConfiguredObservable.clear();
+
         if (this.sceneOptimizer) {
             this.sceneOptimizer.stop();
             this.sceneOptimizer.dispose();

+ 23 - 0
Viewer/src/viewer/viewer.ts

@@ -12,6 +12,7 @@ import { ModelLoader } from '../model/modelLoader';
 import { CameraBehavior } from '../interfaces';
 import { viewerGlobals } from '../configuration/globals';
 import { extendClassWithConfig } from '../helper';
+import { telemetryManager } from '..';
 
 /**
  * The AbstractViewr is the center of Babylon's viewer.
@@ -385,6 +386,8 @@ export abstract class AbstractViewer {
             this.sceneManager.scene.activeCamera.detachControl(this.canvas);
         }
 
+        this._fpsTimeout && clearTimeout(this._fpsTimeout);
+
 
         this.sceneManager.dispose();
 
@@ -571,6 +574,26 @@ export abstract class AbstractViewer {
         })
     }
 
+    private _fpsTimeout: number;
+
+    protected initTelemetryEvents() {
+        telemetryManager.broadcast("Engine Capabilities", this, this.engine.getCaps());
+        telemetryManager.broadcast("Platform Details", this, {
+            userAgent: navigator.userAgent,
+            platform: navigator.platform
+        });
+
+        telemetryManager.flushWebGLErrors(this);
+
+        let trackFPS: Function = () => {
+            telemetryManager.broadcast("Current FPS", this, { fps: this.engine.getFps() });
+        };
+
+        trackFPS();
+        // Track the FPS again after 60 seconds
+        this._fpsTimeout = window.setTimeout(trackFPS, 60 * 1000);
+    }
+
     /**
      * Injects all the spectre shader in the babylon shader store
      */