@aicore/core-analytics-client-lib 1.0.6 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -5
- package/dist/analytics.min.js +3 -3
- package/dist/analytics.min.js.map +1 -1
- package/package.json +1 -1
- package/src/analytics.js +100 -50
package/README.md
CHANGED
|
@@ -39,6 +39,8 @@ in the `initAnalyticsSession` call below:
|
|
|
39
39
|
```
|
|
40
40
|
This will create a global `analytics` variable which can be used to access the analytics APIs.
|
|
41
41
|
|
|
42
|
+
NB: The script is loaded async, so it will not block other js scripts. `analytics.event` api can be called anytime
|
|
43
|
+
after the above code and need not wait for the script load to complete.
|
|
42
44
|
|
|
43
45
|
## Raising analytics events
|
|
44
46
|
We can now start logging analytics events by calling `analytics.event` API.
|
|
@@ -72,6 +74,37 @@ analytics.event("platform", "CPU", "coreCountsAndFrequencyMhz", 8, 2300);
|
|
|
72
74
|
|
|
73
75
|
|
|
74
76
|
## Advanced Usages
|
|
77
|
+
|
|
78
|
+
### Pure JS loading instead of HTML scripts
|
|
79
|
+
|
|
80
|
+
There may be cases where you would want to load the script from JS alone. For Eg. you
|
|
81
|
+
may want to delay library loading till user consents GDPR. For such use cases, use the below code.
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
function _initCoreAnalytics() {
|
|
85
|
+
// Load core analytics scripts
|
|
86
|
+
if(!window.analytics){ window.analytics = {
|
|
87
|
+
_initData: [], loadStartTime: new Date().getTime(),
|
|
88
|
+
event: function (){window.analytics._initData.push(arguments);}
|
|
89
|
+
};}
|
|
90
|
+
let script = document.createElement('script');
|
|
91
|
+
script.type = 'text/javascript';
|
|
92
|
+
script.async = true;
|
|
93
|
+
script.onload = function(){
|
|
94
|
+
// replace `your_analytics_account_ID` and `appName` below with your values
|
|
95
|
+
window.initAnalyticsSession('your_analytics_account_ID', 'appName'); // if you have a custom analytics server
|
|
96
|
+
window.analytics.event("core-analytics", "client-lib", "loadTime", 1,
|
|
97
|
+
(new Date().getTime())- window.analytics.loadStartTime);
|
|
98
|
+
};
|
|
99
|
+
script.src = 'https://unpkg.com/@aicore/core-analytics-client-lib/dist/analytics.min.js';
|
|
100
|
+
document.getElementsByTagName('head')[0].appendChild(script);
|
|
101
|
+
}
|
|
102
|
+
_initCoreAnalytics();
|
|
103
|
+
```
|
|
104
|
+
To load the library, just call `_initCoreAnalytics()` from JS. Note that you may not be able
|
|
105
|
+
to use `analytics.event()` APIs before `_initCoreAnalytics()` call is made.
|
|
106
|
+
|
|
107
|
+
### initAnalyticsSession: modify when, where and how analytics lib sends events
|
|
75
108
|
If you want to modify how analytics library collects and sends information, it is recommended to do so
|
|
76
109
|
with analytics server [accountConfig](https://github.com/aicore/Core-Analytics-Server#accountconfig-configuration).
|
|
77
110
|
|
|
@@ -80,14 +113,14 @@ during the `initAnalyticsSession` call. `initAnalyticsSession()` takes the follo
|
|
|
80
113
|
|
|
81
114
|
* `accountID`: Your analytics account id as configured in the server or core.ai analytics
|
|
82
115
|
* `appName`: The app name to log the events against. Eg: "phoenixCode"
|
|
83
|
-
* `
|
|
116
|
+
* `analyticsURL` (_Optional_): Provide your own analytics server address if you self-hosted the server.
|
|
117
|
+
* `postIntervalSeconds` (_Optional_): This defines the interval between sending analytics events to the server. Default is 1 minutes or server controlled.
|
|
84
118
|
* `granularitySec` (_Optional_): The smallest time period under which the events can be distinguished. Multiple
|
|
85
|
-
events happening during this time period is aggregated to a count. The default granularity is 3 Seconds
|
|
86
|
-
that any events that happen within 3 seconds cannot be distinguished in ordering.
|
|
87
|
-
* `analyticsURL` (_Optional_): Provide your own analytics server address if you self-hosted the server
|
|
119
|
+
events happening during this time period is aggregated to a count. The default granularity is 3 Seconds or server controlled,
|
|
120
|
+
which means that any events that happen within 3 seconds cannot be distinguished in ordering.
|
|
88
121
|
* `debug` (_Optional_): set to true if you want to see detailed debug logs.
|
|
89
122
|
|
|
90
|
-
|
|
123
|
+
#### usageExample
|
|
91
124
|
```javascript
|
|
92
125
|
// Init with default values and server controlled config. use the following `analyticsLibLoaded` function
|
|
93
126
|
function analyticsLibLoaded() {
|
|
@@ -101,12 +134,22 @@ function analyticsLibLoaded() {
|
|
|
101
134
|
// is posted to custom server https://localhost:3000 every 600 secs
|
|
102
135
|
// with a granularity(resolution) of 5 seconds.
|
|
103
136
|
initAnalyticsSession("accountID", "appName", "https://localhost:3000", 600, 5);
|
|
137
|
+
```
|
|
104
138
|
|
|
139
|
+
### Debug logs
|
|
140
|
+
If you want to see detailed logs on what is happening inside analytics lib, use the below code:
|
|
141
|
+
```js
|
|
105
142
|
// To initSession in debug mode set debug arg in init to true. In debug mode, details logs
|
|
106
143
|
// about analytics library events will be emitted.
|
|
107
144
|
initAnalyticsSession("accountID", "appName", "https://localhost:3000", 600, 5, true);
|
|
108
145
|
```
|
|
109
146
|
|
|
147
|
+
To see info level logs that shows actual analytics data being sent to server, set the below property:
|
|
148
|
+
```js
|
|
149
|
+
window.analytics.debugInfoLogsEnable = true;
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
|
|
110
153
|
# Contribute to core-analytics-client-lib
|
|
111
154
|
|
|
112
155
|
## Building
|
package/dist/analytics.min.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
function initAnalyticsSession(e,t,n,a,o,i){let r,s,l,u,c,f,
|
|
2
|
-
typically means that you may be sending too many value events? .`),
|
|
3
|
-
postIntervalSeconds:${c}, granularitySec: ${f} ,URL: `+
|
|
1
|
+
function initAnalyticsSession(e,t,n,a,o,i){let r,s,l,u,c,f,d,y,v={};const g="aicore.analytics.userID",p="aicore.analytics.sessionID",O=1e4;let m=null;var h,w,b,J="undefined"==typeof window;let C="https://analytics.core.ai",I,S,D=0,E=!1,T=!1;function U(...e){T&&console.log("analytics client: ",...e)}function A(...e){T&&console.error("analytics client: ",...e)}if(J)throw new Error("Node environment is not currently supported");function N(){return{schemaVersion:1,accountID:r,appName:s,uuid:l,sessionID:u,unixTimestampUTC:+new Date,numEventsTotal:0,events:{}}}function $(){if(!m)throw new Error("Please call initSession before using any analytics event")}function k(e){e.backoffCount=(e.backoffCount||0)+1,U(`Failed to call core analytics server. Will retry in ${30*e.backoffCount}s: `),setTimeout(()=>{L(e)},3e4*e.backoffCount)}function P(t){var e,n=JSON.stringify(t);n.length>O&&console.warn(`Analytics event generated is very large at greater than ${n.length}B. This
|
|
2
|
+
typically means that you may be sending too many value events? .`),U("Sending Analytics data of length: ",n.length,"B"),e=["Sending data:",n],T&&window.analytics.debugInfoLogsEnable&&console.info("analytics client: ",...e),window.navigator.onLine?window.fetch(y,{method:"POST",headers:{"Content-Type":"application/json"},body:n}).then(e=>{200!==e.status&&(400!==e.status?k(t):console.error("Bad Request, this is most likely a problem with the library, update to latest version."))}).catch(e=>{A(e),k(t)}):k(t)}function L(e){E||(e||(e=m,D=0,R(),m=N()),0!==e.numEventsTotal&&P(e))}function R(e){I&&(clearInterval(I),I=null),e||(I=setInterval(()=>{D+=f},1e3*f))}function _(e){R(e),S&&(clearInterval(S),S=null),e||(S=setInterval(L,1e3*c))}function B(n,a,o,i=1,r=0){if(!E){var s=n,l=a,u=o,c=i,f=r;if($(),!s||!l||!u)throw new Error("missing eventType or category or subCategory");if("number"!=typeof c||c<0)throw new Error("invalid count, count should be a positive number");if("number"!=typeof f)throw new Error("invalid value, value should be a number");{s=n;l=a;u=o;let e=m.events;e[s]=e[s]||{},e[s][l]=e[s][l]||{},e[s][l][u]=e[s][l][u]||{time:[],valueCount:[]}}let t=m.events;c=t[n][a][o].time;if((0<c.length?c[c.length-1]:null)===D){f=t[n][a][o].valueCount.length-1;{var s=f,l=n,u=a,c=o,f=i,d=r;let t=m.events;var e="number"==typeof t[l][u][c].valueCount[s];if(e&&0===d)t[l][u][c].valueCount[s]+=f;else if(e&&0!==d){let e={};e[d]=f,e[0]=t[l][u][c].valueCount[s],t[l][u][c].valueCount[s]=e}else if(!e){let e=t[l][u][c].valueCount[s];e[d]=(e[d]||0)+f}m.numEventsTotal+=1}}else{if(t[n][a][o].time.push(D),0===r)t[n][a][o].valueCount.push(i);else{let e={};e[r]=i,t[n][a][o].valueCount.push(e)}m.numEventsTotal+=1}}}if(!e||!t)throw new Error("accountID and appName must exist for init");d=n?n.toString().replace(/\/$/,""):C,r=e,s=t,T=i||!1,c=a||60,f=o||3,y=d+"/ingest",l=function(){let e=localStorage.getItem(g);return e||(e=crypto.randomUUID(),localStorage.setItem(g,e)),e}(),u=function(){let e=sessionStorage.getItem(p);return e||(e=Math.random().toString(36).substr(2,10),sessionStorage.setItem(p,e)),e}(),m=N(),_(),h=a,w=o,new Promise(t=>{var e;window.navigator.onLine?(e=d+(`/getAppConfig?accountID=${r}&appName=`+s),window.fetch(e).then(e=>{switch(e.status){case 200:return void e.json().then(e=>{t(e)}).catch(e=>{A("remote response invalid. Continuing with defaults.",e),t({})});case 400:A("Bad Request, check library version compatible?",e),t({});break;default:A("Could not update from remote config. Continuing with defaults.",e),t({})}}).catch(e=>{A("Could not update from remote config. Continuing with defaults.",e),t({})})):t({})}).then(e=>{v!=={}&&(v=e,c=h||v.postIntervalSecondsInit||60,f=w||v.granularitySecInit||3,d=v.analyticsURLInit||d||C,_(E=!0===v.disabled),U(`Init analytics Config from remote. disabled: ${E}
|
|
3
|
+
postIntervalSeconds:${c}, granularitySec: ${f} ,URL: `+d),E&&console.warn(`Core Analytics is disabled from the server for app: ${r}:`+s))});for(b of analytics._initData)B(...b);analytics._initData=[],analytics._getCurrentAnalyticsEvent=function(){return $(),JSON.parse(JSON.stringify(m))},analytics._getAppConfig=function(){return{accountID:r,appName:s,disabled:E,uuid:l,sessionID:u,postIntervalSeconds:c,granularitySec:f,analyticsURL:d,serverConfig:v}},analytics.event=B}window.analytics||(window.analytics={_initData:[]}),void 0===window.crypto&&(window.crypto={}),"randomUUID"in crypto||(crypto.randomUUID=function(){return([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,e=>(e^crypto.getRandomValues(new Uint8Array(1))[0]&15>>e/4).toString(16))});
|
|
4
4
|
//# sourceMappingURL=analytics.min.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sourceRoot":"src/analytics.js","sources":["src/analytics.js"],"names":["initAnalyticsSession","accountIDInit","appNameInit","analyticsURLInit","postIntervalSecondsInit","granularitySecInit","debug","let","accountID","appName","userID","sessionID","postIntervalSeconds","granularitySec","analyticsURL","postURL","serverConfig","
|
|
1
|
+
{"version":3,"sourceRoot":"src/analytics.js","sources":["src/analytics.js"],"names":["initAnalyticsSession","accountIDInit","appNameInit","analyticsURLInit","postIntervalSecondsInit","granularitySecInit","debug","let","accountID","appName","userID","sessionID","postIntervalSeconds","granularitySec","analyticsURL","postURL","serverConfig","USERID_LOCAL_STORAGE_KEY","SESSION_ID_LOCAL_STORAGE_KEY","POST_LARGE_DATA_THRESHOLD_BYTES","currentAnalyticsEvent","postIntervalSecondsInitial","granularitySecInitial","eventData","IS_NODE_ENV","window","DEFAULT_BASE_URL","granularityTimer","postTimer","currentQuantisedTime","disabled","debugMode","debugLog","args","console","log","debugError","error","Error","_createAnalyticsEvent","schemaVersion","uuid","unixTimestampUTC","Date","numEventsTotal","events","_validateCurrentState","_retryPost","eventToSend","backoffCount","setTimeout","_postCurrentAnalyticsEvent","DEFAULT_RETRY_TIME_IN_SECONDS","_postEventWithRetry","textToSend","JSON","stringify","length","warn","debugInfo","analytics","debugInfoLogsEnable","info","navigator","onLine","fetch","method","headers","Content-Type","body","then","res","status","catch","_resetGranularityTimer","disable","clearInterval","setInterval","_setupTimers","event","eventType","eventCategory","subCategory","eventCount","eventValue","_validateEvent","category","count","value","_ensureAnalyticsEventExists","time","valueCount","timeArray","modificationIndex","_updateExistingAnalyticsEvent","index","newValue","storedValueIsCount","newValueCount","storedValueObject","push","toString","replace","localUserID","localStorage","getItem","crypto","randomUUID","setItem","_getOrCreateUserID","localSessionID","sessionStorage","Math","random","substr","_getOrCreateSessionID","Promise","configURL","json","serverResponse","resolve","err","updatedServerConfig","_initData","_getCurrentAnalyticsEvent","parse","_getAppConfig","c","getRandomValues","Uint8Array"],"mappings":"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"}
|
package/package.json
CHANGED
package/src/analytics.js
CHANGED
|
@@ -10,16 +10,32 @@ if(!window.analytics){
|
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
if (typeof window.crypto === 'undefined'){
|
|
14
|
+
window.crypto = {};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!('randomUUID' in crypto)){
|
|
18
|
+
// https://stackoverflow.com/a/2117523/2800218
|
|
19
|
+
// LICENSE: https://creativecommons.org/licenses/by-sa/4.0/legalcode
|
|
20
|
+
crypto.randomUUID = function randomUUID() {
|
|
21
|
+
return (
|
|
22
|
+
[1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,
|
|
23
|
+
// eslint-disable-next-line no-bitwise
|
|
24
|
+
c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
13
29
|
/**
|
|
14
30
|
* Initialize the analytics session
|
|
15
31
|
* @param accountIDInit Your analytics account id as configured in the server or core.ai analytics
|
|
16
32
|
* @param appNameInit The app name to log the events against.
|
|
17
|
-
* @param analyticsURLInit Optional: Provide your own analytics server address if you self-hosted the server
|
|
33
|
+
* @param analyticsURLInit Optional: Provide your own analytics server address if you self-hosted the server.
|
|
18
34
|
* @param postIntervalSecondsInit Optional: This defines the interval between sending analytics events to the server.
|
|
19
|
-
* Default is
|
|
35
|
+
* Default is 1 minutes or server controlled.
|
|
20
36
|
* @param granularitySecInit Optional: The smallest time period under which the events can be distinguished. Multiple
|
|
21
|
-
* events happening during this time period is aggregated to a count. The default granularity is 3 Seconds
|
|
22
|
-
* that any events that happen within 3 seconds cannot be distinguished in ordering.
|
|
37
|
+
* events happening during this time period is aggregated to a count. The default granularity is 3 Seconds or server
|
|
38
|
+
* controlled, which means that any events that happen within 3 seconds cannot be distinguished in ordering.
|
|
23
39
|
* @param debug set to true if you want to see detailed debug logs.
|
|
24
40
|
*/
|
|
25
41
|
function initAnalyticsSession(accountIDInit, appNameInit, analyticsURLInit,
|
|
@@ -28,8 +44,9 @@ function initAnalyticsSession(accountIDInit, appNameInit, analyticsURLInit,
|
|
|
28
44
|
granularitySec, analyticsURL, postURL, serverConfig={};
|
|
29
45
|
const DEFAULT_GRANULARITY_IN_SECONDS = 3;
|
|
30
46
|
const DEFAULT_RETRY_TIME_IN_SECONDS = 30;
|
|
31
|
-
const DEFAULT_POST_INTERVAL_SECONDS =
|
|
47
|
+
const DEFAULT_POST_INTERVAL_SECONDS = 60; // 1 minutes
|
|
32
48
|
const USERID_LOCAL_STORAGE_KEY = 'aicore.analytics.userID';
|
|
49
|
+
const SESSION_ID_LOCAL_STORAGE_KEY = 'aicore.analytics.sessionID';
|
|
33
50
|
const POST_LARGE_DATA_THRESHOLD_BYTES = 10000;
|
|
34
51
|
let currentAnalyticsEvent = null;
|
|
35
52
|
const IS_NODE_ENV = (typeof window === 'undefined');
|
|
@@ -45,14 +62,20 @@ function initAnalyticsSession(accountIDInit, appNameInit, analyticsURLInit,
|
|
|
45
62
|
if(!debugMode){
|
|
46
63
|
return;
|
|
47
64
|
}
|
|
48
|
-
console.log(...args);
|
|
65
|
+
console.log("analytics client: ", ...args);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function debugInfo(...args) {
|
|
69
|
+
if(debugMode && window.analytics.debugInfoLogsEnable){
|
|
70
|
+
console.info("analytics client: ", ...args);
|
|
71
|
+
}
|
|
49
72
|
}
|
|
50
73
|
|
|
51
74
|
function debugError(...args) {
|
|
52
75
|
if(!debugMode){
|
|
53
76
|
return;
|
|
54
77
|
}
|
|
55
|
-
console.error(...args);
|
|
78
|
+
console.error("analytics client: ", ...args);
|
|
56
79
|
}
|
|
57
80
|
|
|
58
81
|
|
|
@@ -95,10 +118,10 @@ function initAnalyticsSession(accountIDInit, appNameInit, analyticsURLInit,
|
|
|
95
118
|
}
|
|
96
119
|
|
|
97
120
|
function _getOrCreateSessionID() {
|
|
98
|
-
let localSessionID = sessionStorage.getItem(
|
|
121
|
+
let localSessionID = sessionStorage.getItem(SESSION_ID_LOCAL_STORAGE_KEY);
|
|
99
122
|
if(!localSessionID){
|
|
100
123
|
localSessionID = Math.random().toString(36).substr(2, 10);
|
|
101
|
-
sessionStorage.setItem(
|
|
124
|
+
sessionStorage.setItem(SESSION_ID_LOCAL_STORAGE_KEY, localSessionID);
|
|
102
125
|
}
|
|
103
126
|
return localSessionID;
|
|
104
127
|
}
|
|
@@ -117,25 +140,20 @@ function initAnalyticsSession(accountIDInit, appNameInit, analyticsURLInit,
|
|
|
117
140
|
}, DEFAULT_RETRY_TIME_IN_SECONDS * 1000 * eventToSend.backoffCount);
|
|
118
141
|
}
|
|
119
142
|
|
|
120
|
-
function
|
|
121
|
-
if(disabled){
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if(!eventToSend){
|
|
125
|
-
eventToSend = currentAnalyticsEvent;
|
|
126
|
-
currentQuantisedTime = 0;
|
|
127
|
-
_resetGranularityTimer();
|
|
128
|
-
currentAnalyticsEvent = _createAnalyticsEvent();
|
|
129
|
-
}
|
|
130
|
-
if(eventToSend.numEventsTotal === 0 ){
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
143
|
+
function _postEventWithRetry(eventToSend) {
|
|
133
144
|
let textToSend = JSON.stringify(eventToSend);
|
|
134
145
|
if(textToSend.length > POST_LARGE_DATA_THRESHOLD_BYTES){
|
|
135
146
|
console.warn(`Analytics event generated is very large at greater than ${textToSend.length}B. This
|
|
136
147
|
typically means that you may be sending too many value events? .`);
|
|
137
148
|
}
|
|
138
149
|
debugLog("Sending Analytics data of length: ", textToSend.length, "B");
|
|
150
|
+
debugInfo("Sending data:", textToSend);
|
|
151
|
+
if(!window.navigator.onLine){
|
|
152
|
+
_retryPost(eventToSend);
|
|
153
|
+
// chrome shows all network failure requests in console. In offline mode, we don't want to bomb debug
|
|
154
|
+
// console with network failure messages for analytics. So we prevent network requests when offline.
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
139
157
|
window.fetch(postURL, {
|
|
140
158
|
method: "POST",
|
|
141
159
|
headers: {'Content-Type': 'application/json'},
|
|
@@ -147,8 +165,7 @@ function initAnalyticsSession(accountIDInit, appNameInit, analyticsURLInit,
|
|
|
147
165
|
if(res.status !== 400){ // we don't retry bad requests
|
|
148
166
|
_retryPost(eventToSend);
|
|
149
167
|
} else {
|
|
150
|
-
console.error("
|
|
151
|
-
"Bad Request, this is most likely a problem with the library, update to latest version.");
|
|
168
|
+
console.error("Bad Request, this is most likely a problem with the library, update to latest version.");
|
|
152
169
|
}
|
|
153
170
|
}).catch(res => {
|
|
154
171
|
debugError(res);
|
|
@@ -156,6 +173,22 @@ function initAnalyticsSession(accountIDInit, appNameInit, analyticsURLInit,
|
|
|
156
173
|
});
|
|
157
174
|
}
|
|
158
175
|
|
|
176
|
+
function _postCurrentAnalyticsEvent(eventToSend) {
|
|
177
|
+
if(disabled){
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if(!eventToSend){
|
|
181
|
+
eventToSend = currentAnalyticsEvent;
|
|
182
|
+
currentQuantisedTime = 0;
|
|
183
|
+
_resetGranularityTimer();
|
|
184
|
+
currentAnalyticsEvent = _createAnalyticsEvent();
|
|
185
|
+
}
|
|
186
|
+
if(eventToSend.numEventsTotal === 0 ){
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
_postEventWithRetry(eventToSend);
|
|
190
|
+
}
|
|
191
|
+
|
|
159
192
|
function _resetGranularityTimer(disable) {
|
|
160
193
|
if(granularityTimer){
|
|
161
194
|
clearInterval(granularityTimer);
|
|
@@ -181,23 +214,36 @@ function initAnalyticsSession(accountIDInit, appNameInit, analyticsURLInit,
|
|
|
181
214
|
postTimer = setInterval(_postCurrentAnalyticsEvent, postIntervalSeconds*1000);
|
|
182
215
|
}
|
|
183
216
|
|
|
184
|
-
|
|
185
|
-
return new Promise((resolve
|
|
217
|
+
function _getServerConfig() {
|
|
218
|
+
return new Promise((resolve)=>{
|
|
219
|
+
if(!window.navigator.onLine){
|
|
220
|
+
resolve({});
|
|
221
|
+
// chrome shows all network failure requests in console. In offline mode, we don't want to bomb debug
|
|
222
|
+
// console with network failure messages for analytics. So we prevent network requests when offline.
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
186
225
|
let configURL = analyticsURL + `/getAppConfig?accountID=${accountID}&appName=${appName}`;
|
|
187
|
-
window.fetch(configURL).then(
|
|
226
|
+
window.fetch(configURL).then(res=>{
|
|
188
227
|
switch (res.status) {
|
|
189
228
|
case 200:
|
|
190
|
-
|
|
191
|
-
|
|
229
|
+
res.json().then(serverResponse =>{
|
|
230
|
+
resolve(serverResponse);
|
|
231
|
+
}).catch(err => {
|
|
232
|
+
debugError("remote response invalid. Continuing with defaults.", err);
|
|
233
|
+
resolve({});
|
|
234
|
+
});
|
|
192
235
|
return;
|
|
193
236
|
case 400:
|
|
194
|
-
|
|
237
|
+
debugError("Bad Request, check library version compatible?", res);
|
|
238
|
+
resolve({});
|
|
195
239
|
break;
|
|
196
240
|
default:
|
|
197
|
-
|
|
241
|
+
debugError("Could not update from remote config. Continuing with defaults.", res);
|
|
242
|
+
resolve({});
|
|
198
243
|
}
|
|
199
244
|
}).catch(err => {
|
|
200
|
-
|
|
245
|
+
debugError("Could not update from remote config. Continuing with defaults.", err);
|
|
246
|
+
resolve({});
|
|
201
247
|
});
|
|
202
248
|
});
|
|
203
249
|
}
|
|
@@ -214,27 +260,29 @@ function initAnalyticsSession(accountIDInit, appNameInit, analyticsURLInit,
|
|
|
214
260
|
};
|
|
215
261
|
}
|
|
216
262
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
263
|
+
function _initFromRemoteConfig(postIntervalSecondsInitial, granularitySecInitial) {
|
|
264
|
+
_getServerConfig().then(updatedServerConfig =>{
|
|
265
|
+
if(serverConfig !== {}){
|
|
266
|
+
serverConfig = updatedServerConfig;
|
|
267
|
+
// User init overrides takes precedence over server overrides
|
|
268
|
+
postIntervalSeconds = postIntervalSecondsInitial ||
|
|
269
|
+
serverConfig["postIntervalSecondsInit"] || DEFAULT_POST_INTERVAL_SECONDS;
|
|
270
|
+
granularitySec = granularitySecInitial || serverConfig["granularitySecInit"] || DEFAULT_GRANULARITY_IN_SECONDS;
|
|
271
|
+
// For URLs, the server suggested URL takes precedence over user init values
|
|
272
|
+
analyticsURL = serverConfig["analyticsURLInit"] || analyticsURL || DEFAULT_BASE_URL;
|
|
273
|
+
disabled = serverConfig["disabled"] === true;
|
|
274
|
+
_setupTimers(disabled);
|
|
275
|
+
debugLog(`Init analytics Config from remote. disabled: ${disabled}
|
|
229
276
|
postIntervalSeconds:${postIntervalSeconds}, granularitySec: ${granularitySec} ,URL: ${analyticsURL}`);
|
|
230
|
-
|
|
231
|
-
|
|
277
|
+
if(disabled){
|
|
278
|
+
console.warn(`Core Analytics is disabled from the server for app: ${accountID}:${appName}`);
|
|
279
|
+
}
|
|
232
280
|
}
|
|
233
|
-
}
|
|
281
|
+
});
|
|
234
282
|
}
|
|
235
283
|
|
|
236
284
|
function _stripTrailingSlash(url) {
|
|
237
|
-
return url.replace(/\/$/, "");
|
|
285
|
+
return url.toString().replace(/\/$/, "");
|
|
238
286
|
}
|
|
239
287
|
|
|
240
288
|
function _ensureAnalyticsEventExists(eventType, category, subCategory) {
|
|
@@ -242,8 +290,10 @@ function initAnalyticsSession(accountIDInit, appNameInit, analyticsURLInit,
|
|
|
242
290
|
events[eventType] = events[eventType] || {};
|
|
243
291
|
events[eventType][category] = events[eventType][category] || {};
|
|
244
292
|
events[eventType][category][subCategory] = events[eventType][category][subCategory] || {
|
|
245
|
-
|
|
246
|
-
|
|
293
|
+
// quantised time
|
|
294
|
+
time: [],
|
|
295
|
+
// value and count array, If a single value, then it is count, else object {"val1":count1, ...}
|
|
296
|
+
valueCount: []
|
|
247
297
|
};
|
|
248
298
|
}
|
|
249
299
|
|