@aicore/core-analytics-client-lib 1.0.5 → 1.0.8

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 CHANGED
@@ -20,41 +20,31 @@ events for [Core-Analytics-Server](https://github.com/aicore/Core-Analytics-Serv
20
20
  # Usage
21
21
 
22
22
  ## Load the Library
23
- Embed the script in your HTML file :
23
+ Embed the script in your HTML file and replace `your_analytics_account_ID` and `appName`
24
+ in the `initAnalyticsSession` call below:
24
25
  ```html
25
- <script src="https://unpkg.com/@aicore/core-analytics-client-lib/src/analytics.js"></script>
26
+ <!-- Global window.analytics object - core.ai analytics services -->
27
+ <script async src="https://unpkg.com/@aicore/core-analytics-client-lib/src/analytics.js"
28
+ onload="analyticsLibLoaded()"></script>
29
+ <script>
30
+ if(!window.analytics){ window.analytics = {
31
+ _initData : [], loadStartTime: new Date().getTime(),
32
+ event: function (){window.analytics._initData.push(arguments);}
33
+ };}
34
+ function analyticsLibLoaded() {
35
+ initAnalyticsSession('your_analytics_account_ID', 'appName');
36
+ analytics.event("core-analytics", "client-lib", "loadTime", 1, (new Date().getTime())-analytics.loadStartTime);
37
+ }
38
+ </script>
26
39
  ```
27
40
  This will create a global `analytics` variable which can be used to access the analytics APIs.
28
41
 
29
- ## Initialize the analytics session.
30
- Call `analytics.initSession()` after loading the library. It takes the following parameters:
31
-
32
- * `accountID`: Your analytics account id as configured in the server or core.ai analytics
33
- * `appName`: The app name to log the events against. Eg: "phoenixCode"
34
- * `postIntervalSeconds` (_Optional_): This defines the interval between sending analytics events to the server. Default is 10 minutes
35
- * `granularitySec` (_Optional_): The smallest time period under which the events can be distinguished. Multiple
36
- events happening during this time period is aggregated to a count. The default granularity is 3 Seconds, which means
37
- that any events that happen within 3 seconds cannot be distinguished in ordering.
38
- * `analyticsURL` (_Optional_): Provide your own analytics server address if you self-hosted the server
39
- * `debug` (_Optional_): set to true if you want to see detailed debug logs.
40
-
41
- ### usageExample
42
- ```javascript
43
- // Init with default values.
44
- analytics.initSession("accountID", "appName");
45
-
46
- // Example for custom initSession where the analytics aggregated data
47
- // is posted to custom server https://localhost:3000 every 600 secs
48
- // with a granularity(resolution) of 5 seconds.
49
- analytics.initSession("accountID", "appName", "https://localhost:3000", 600, 5);
50
-
51
- // To initSession in debug mode set debug arg in init to true:
52
- analytics.initSession("accountID", "appName", "https://localhost:3000", 600, 5, true);
53
- ```
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.
54
44
 
55
45
  ## Raising analytics events
56
- Once `initSession` is called, we can now start logging analytics events by calling `analytics.event` API.
57
- The API registers an analytics event. The events will be aggregated and send to the analytics server periodically.
46
+ We can now start logging analytics events by calling `analytics.event` API.
47
+ The events will be aggregated and send to the analytics server periodically.
58
48
 
59
49
  ```javascript
60
50
  // analyticsEvent(eventType, eventCategory, subCategory, eventCount, eventValue);
@@ -79,9 +69,87 @@ analytics.event("platform", "CPU", "coreCountsAndFrequencyMhz", 8, 2300);
79
69
  * `eventCategory` - A string, required
80
70
  * `subCategory` - A string, required
81
71
  * `eventCount` (_Optional_) : A non-negative number indicating the number of times the event (or an event with a
82
- particular value if a value is specified) happened. defaults to 1.
72
+ particular value if a value is specified) happened. defaults to 1.
83
73
  * `eventValue` (_Optional_) : A number value associated with the event. defaults to 0
84
74
 
75
+
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
108
+ If you want to modify how analytics library collects and sends information, it is recommended to do so
109
+ with analytics server [accountConfig](https://github.com/aicore/Core-Analytics-Server#accountconfig-configuration).
110
+
111
+ Alternatively for one off development time uses, the behavior of the library can be configured
112
+ during the `initAnalyticsSession` call. `initAnalyticsSession()` takes the following parameters:
113
+
114
+ * `accountID`: Your analytics account id as configured in the server or core.ai analytics
115
+ * `appName`: The app name to log the events against. Eg: "phoenixCode"
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.
118
+ * `granularitySec` (_Optional_): The smallest time period under which the events can be distinguished. Multiple
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.
121
+ * `debug` (_Optional_): set to true if you want to see detailed debug logs.
122
+
123
+ #### usageExample
124
+ ```javascript
125
+ // Init with default values and server controlled config. use the following `analyticsLibLoaded` function
126
+ function analyticsLibLoaded() {
127
+ initAnalyticsSession('your_analytics_account_ID', 'appName');
128
+ analytics.event("core-analytics", "client-lib", "loadTime", 1, (new Date().getTime())-analytics.loadStartTime);
129
+ }
130
+
131
+ //Replace initAnalyticsSession in analyticsLibLoaded function for the below use cases.
132
+
133
+ // Example for custom initSession where the analytics aggregated data
134
+ // is posted to custom server https://localhost:3000 every 600 secs
135
+ // with a granularity(resolution) of 5 seconds.
136
+ initAnalyticsSession("accountID", "appName", "https://localhost:3000", 600, 5);
137
+ ```
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
142
+ // To initSession in debug mode set debug arg in init to true. In debug mode, details logs
143
+ // about analytics library events will be emitted.
144
+ initAnalyticsSession("accountID", "appName", "https://localhost:3000", 600, 5, true);
145
+ ```
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
+
85
153
  # Contribute to core-analytics-client-lib
86
154
 
87
155
  ## Building
@@ -1,4 +1,4 @@
1
- var analytics={};function init(){let r,s,e,t,l,u,c,f,n;const v=3,a=30,y=600,o="aicore.analytics.userID",i=1e4;let d=null;var m="undefined"==typeof window;let g="https://analytics.core.ai",p,h,w=0,C=!1,I=!1;function b(...e){I&&console.log(...e)}if(m)throw new Error("Node environment is not currently supported");function S(){return{schemaVersion:1,accountID:r,appName:s,uuid:e,sessionID:t,unixTimestampUTC:+new Date,numEventsTotal:0,events:{}}}function E(){if(!d)throw new Error("Please call initSession before using any analytics event")}function T(){e=function(){let e=localStorage.getItem(o);return e||(e=crypto.randomUUID(),localStorage.setItem(o,e)),e}(),t=function(){let e=sessionStorage.getItem(o);return e||(e=Math.random().toString(36).substr(2,10),sessionStorage.setItem(o,e)),e}()}function D(e){e.backoffCount=(e.backoffCount||0)+1,b(`Failed to call core analytics server. Will retry in ${a*e.backoffCount}s: `),setTimeout(()=>{N(e)},1e3*a*e.backoffCount)}function N(t){var e;C||(t||(t=d,w=0,$(),d=S()),0!==t.numEventsTotal&&((e=JSON.stringify(t)).length>i&&console.warn(`Analytics event generated is very large at greater than ${e.length}B. This
2
- typically means that you may be sending too many value events? .`),b("Sending Analytics data of length: ",e.length,"B"),window.fetch(f,{method:"POST",headers:{"Content-Type":"application/json"},body:e}).then(e=>{200!==e.status&&(400!==e.status?D(t):console.error("Analytics client: Bad Request, this is most likely a problem with the library, update to latest version."))}).catch(e=>{e=[e],I&&console.error(...e),D(t)})))}function $(e){p&&(clearInterval(p),p=null),e||(p=setInterval(()=>{w+=u},1e3*u))}function k(e){$(e),h&&(clearInterval(h),h=null),e||(h=setInterval(N,1e3*l))}async function A(e,t){(n=await new Promise((n,a)=>{var e=c+(`/getAppConfig?accountID=${r}&appName=`+s);window.fetch(e).then(async e=>{switch(e.status){case 200:var t=await e.json();return void n(t);case 400:a("Bad Request, check library version compatible?",e);break;default:a("analytics client: Could not update from remote config. Continuing with defaults.",e)}}).catch(e=>{a("analytics client: Could not update from remote config. Continuing with defaults.",e)})}))!=={}&&(l=e||n.postIntervalSecondsInit||y,u=t||n.granularitySecInit||v,c=n.analyticsURLInit||c||g,k(C=!0===n.disabled),b(`Init analytics Config from remote. disabled: ${C}
3
- postIntervalSeconds:${l}, granularitySec: ${u} ,URL: `+c),C&&console.warn(`Core Analytics is disabled from the server for app: ${r}:`+s))}analytics.initSession=function(e,t,n,a,o,i){if(!e||!t)throw new Error("accountID and appName must exist for init");c=n?n.replace(/\/$/,""):g,r=e,s=t,I=i||!1,l=a||y,u=o||v,f=c+"/ingest",T(),d=S(),k(),A(a,o)},analytics.getCurrentAnalyticsEvent=function(){return E(),JSON.parse(JSON.stringify(d))},analytics.event=function(n,a,o,i=1,r=0){if(!C){var s=n,l=a,u=o,c=i,f=r;if(E(),!s||!l||!u)throw new Error("missing eventType or category or subCategory");if("number"!=typeof c||c<0)throw new Error("invalid count");if("number"!=typeof f)throw new Error("invalid value");{s=n;l=a;u=o;let e=d.events;e[s]=e[s]||{},e[s][l]=e[s][l]||{},e[s][l][u]=e[s][l][u]||{time:[],valueCount:[]}}let t=d.events;c=t[n][a][o].time;if((0<c.length?c[c.length-1]:null)===w){f=t[n][a][o].valueCount.length-1;{var s=f,l=n,u=a,c=o,f=i,v=r;let t=d.events;var e="number"==typeof t[l][u][c].valueCount[s];if(e&&0===v)t[l][u][c].valueCount[s]+=f;else if(e&&0!==v){let e={};e[v]=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[v]=(e[v]||0)+f}d.numEventsTotal+=1}}else{if(t[n][a][o].time.push(w),0===r)t[n][a][o].valueCount.push(i);else{let e={};e[r]=i,t[n][a][o].valueCount.push(e)}d.numEventsTotal+=1}}},analytics.getAppConfig=function(){return{accountID:r,appName:s,disabled:C,uuid:e,sessionID:t,postIntervalSeconds:l,granularitySec:u,analyticsURL:c,serverConfig:n}}}init();
1
+ function initAnalyticsSession(e,t,n,a,o,i){let s,r,l,u,c,f,d,v,y={};const g="aicore.analytics.userID",m="aicore.analytics.sessionID",p=1e4;let h=null;var w,b="undefined"==typeof window;let C="https://analytics.core.ai",I,S,D=0,E=!1,T=!1;function N(...e){T&&console.log("analytics client: ",...e)}function $(...e){T&&console.error("analytics client: ",...e)}if(b)throw new Error("Node environment is not currently supported");function k(){return{schemaVersion:1,accountID:s,appName:r,uuid:l,sessionID:u,unixTimestampUTC:+new Date,numEventsTotal:0,events:{}}}function A(){if(!h)throw new Error("Please call initSession before using any analytics event")}function L(e){e.backoffCount=(e.backoffCount||0)+1,N(`Failed to call core analytics server. Will retry in ${30*e.backoffCount}s: `),setTimeout(()=>{U(e)},3e4*e.backoffCount)}function O(t){var e,n=JSON.stringify(t);n.length>p&&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? .`),N("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(v,{method:"POST",headers:{"Content-Type":"application/json"},body:n}).then(e=>{200!==e.status&&(400!==e.status?L(t):console.error("Bad Request, this is most likely a problem with the library, update to latest version."))}).catch(e=>{$(e),L(t)}):L(t)}function U(e){E||(e||(e=h,D=0,R(),h=k()),0!==e.numEventsTotal&&O(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(U,1e3*c))}function B(n,a,o,i=1,s=0){if(!E){var r=n,l=a,u=o,c=i,f=s;if(A(),!r||!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");{r=n;l=a;u=o;let e=h.events;e[r]=e[r]||{},e[r][l]=e[r][l]||{},e[r][l][u]=e[r][l][u]||{time:[],valueCount:[]}}let t=h.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 r=f,l=n,u=a,c=o,f=i,d=s;let t=h.events;var e="number"==typeof t[l][u][c].valueCount[r];if(e&&0===d)t[l][u][c].valueCount[r]+=f;else if(e&&0!==d){let e={};e[d]=f,e[0]=t[l][u][c].valueCount[r],t[l][u][c].valueCount[r]=e}else if(!e){let e=t[l][u][c].valueCount[r];e[d]=(e[d]||0)+f}h.numEventsTotal+=1}}else{if(t[n][a][o].time.push(D),0===s)t[n][a][o].valueCount.push(i);else{let e={};e[s]=i,t[n][a][o].valueCount.push(e)}h.numEventsTotal+=1}}}if(!e||!t)throw new Error("accountID and appName must exist for init");d=n?n.replace(/\/$/,""):C,s=e,r=t,T=i||!1,c=a||60,f=o||3,v=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(m);return e||(e=Math.random().toString(36).substr(2,10),sessionStorage.setItem(m,e)),e}(),h=k(),_(),async function(e,t){(y=await new Promise(n=>{var e;window.navigator.onLine?(e=d+(`/getAppConfig?accountID=${s}&appName=`+r),window.fetch(e).then(async e=>{switch(e.status){case 200:var t=await e.json();return void n(t);case 400:$("Bad Request, check library version compatible?",e),n({});break;default:$("Could not update from remote config. Continuing with defaults.",e),n({})}}).catch(e=>{$("Could not update from remote config. Continuing with defaults.",e),n({})})):n({})}))!=={}&&(c=e||y.postIntervalSecondsInit||60,f=t||y.granularitySecInit||3,d=y.analyticsURLInit||d||C,_(E=!0===y.disabled),N(`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: ${s}:`+r))}(a,o);for(w of analytics._initData)B(...w);analytics._initData=[],analytics._getCurrentAnalyticsEvent=function(){return A(),JSON.parse(JSON.stringify(h))},analytics._getAppConfig=function(){return{accountID:s,appName:r,disabled:E,uuid:l,sessionID:u,postIntervalSeconds:c,granularitySec:f,analyticsURL:d,serverConfig:y}},analytics.event=B}window.analytics||(window.analytics={_initData:[]});
4
4
  //# sourceMappingURL=analytics.min.js.map
@@ -1 +1 @@
1
- {"version":3,"sourceRoot":"src/analytics.js","sources":["src/analytics.js"],"names":["analytics","init","let","accountID","appName","userID","sessionID","postIntervalSeconds","granularitySec","analyticsURL","postURL","serverConfig","DEFAULT_GRANULARITY_IN_SECONDS","DEFAULT_RETRY_TIME_IN_SECONDS","DEFAULT_POST_INTERVAL_SECONDS","USERID_LOCAL_STORAGE_KEY","POST_LARGE_DATA_THRESHOLD_BYTES","currentAnalyticsEvent","IS_NODE_ENV","window","DEFAULT_BASE_URL","granularityTimer","postTimer","currentQuantisedTime","disabled","debugMode","debugLog","args","console","log","Error","_createAnalyticsEvent","schemaVersion","uuid","unixTimestampUTC","Date","numEventsTotal","events","_validateCurrentState","_setupIDs","localUserID","localStorage","getItem","crypto","randomUUID","setItem","_getOrCreateUserID","localSessionID","sessionStorage","Math","random","toString","substr","_getOrCreateSessionID","_retryPost","eventToSend","backoffCount","setTimeout","_postCurrentAnalyticsEvent","textToSend","_resetGranularityTimer","JSON","stringify","length","warn","fetch","method","headers","Content-Type","body","then","res","status","error","catch","debugError","disable","clearInterval","setInterval","_setupTimers","async","_initFromRemoteConfig","postIntervalSecondsInit","granularitySecInit","Promise","resolve","reject","configURL","serverResponse","json","err","initSession","accountIDInit","appNameInit","analyticsURLInit","debug","replace","getCurrentAnalyticsEvent","parse","event","eventType","eventCategory","subCategory","eventCount","eventValue","_validateEvent","category","count","value","_ensureAnalyticsEventExists","time","valueCount","timeArray","modificationIndex","_updateExistingAnalyticsEvent","index","newValue","storedValueIsCount","newValueCount","storedValueObject","push","getAppConfig"],"mappings":"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"}
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","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","replace","localUserID","localStorage","getItem","crypto","randomUUID","setItem","_getOrCreateUserID","localSessionID","sessionStorage","Math","random","toString","substr","_getOrCreateSessionID","async","postIntervalSecondsInitial","granularitySecInitial","Promise","configURL","serverResponse","json","resolve","err","_initFromRemoteConfig","_initData","_getCurrentAnalyticsEvent","parse","_getAppConfig"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aicore/core-analytics-client-lib",
3
- "version": "1.0.5",
3
+ "version": "1.0.8",
4
4
  "description": "Analytics client library for https://github.com/aicore/Core-Analytics-Server",
5
5
  "main": "dist/analytics.min.js",
6
6
  "type": "module",
package/src/analytics.js CHANGED
@@ -1,16 +1,36 @@
1
1
  // GNU AGPL-3.0 License Copyright (c) 2021 - present core.ai . All rights reserved.
2
2
 
3
3
  // jshint ignore: start
4
- /*global localStorage, sessionStorage, crypto*/
4
+ /*global localStorage, sessionStorage, crypto, analytics*/
5
5
 
6
- var analytics = {};
7
6
 
8
- function init() {
9
- let accountID, appName, userID, sessionID, postIntervalSeconds, granularitySec, analyticsURL, postURL, serverConfig;
7
+ if(!window.analytics){
8
+ window.analytics = {
9
+ _initData: []
10
+ };
11
+ }
12
+
13
+ /**
14
+ * Initialize the analytics session
15
+ * @param accountIDInit Your analytics account id as configured in the server or core.ai analytics
16
+ * @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.
18
+ * @param postIntervalSecondsInit Optional: This defines the interval between sending analytics events to the server.
19
+ * Default is 1 minutes or server controlled.
20
+ * @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 or server
22
+ * controlled, which means that any events that happen within 3 seconds cannot be distinguished in ordering.
23
+ * @param debug set to true if you want to see detailed debug logs.
24
+ */
25
+ function initAnalyticsSession(accountIDInit, appNameInit, analyticsURLInit,
26
+ postIntervalSecondsInit, granularitySecInit, debug) {
27
+ let accountID, appName, userID, sessionID, postIntervalSeconds,
28
+ granularitySec, analyticsURL, postURL, serverConfig={};
10
29
  const DEFAULT_GRANULARITY_IN_SECONDS = 3;
11
30
  const DEFAULT_RETRY_TIME_IN_SECONDS = 30;
12
- const DEFAULT_POST_INTERVAL_SECONDS = 600; // 10 minutes
31
+ const DEFAULT_POST_INTERVAL_SECONDS = 60; // 1 minutes
13
32
  const USERID_LOCAL_STORAGE_KEY = 'aicore.analytics.userID';
33
+ const SESSION_ID_LOCAL_STORAGE_KEY = 'aicore.analytics.sessionID';
14
34
  const POST_LARGE_DATA_THRESHOLD_BYTES = 10000;
15
35
  let currentAnalyticsEvent = null;
16
36
  const IS_NODE_ENV = (typeof window === 'undefined');
@@ -26,14 +46,20 @@ function init() {
26
46
  if(!debugMode){
27
47
  return;
28
48
  }
29
- console.log(...args);
49
+ console.log("analytics client: ", ...args);
50
+ }
51
+
52
+ function debugInfo(...args) {
53
+ if(debugMode && window.analytics.debugInfoLogsEnable){
54
+ console.info("analytics client: ", ...args);
55
+ }
30
56
  }
31
57
 
32
58
  function debugError(...args) {
33
59
  if(!debugMode){
34
60
  return;
35
61
  }
36
- console.error(...args);
62
+ console.error("analytics client: ", ...args);
37
63
  }
38
64
 
39
65
 
@@ -60,7 +86,7 @@ function init() {
60
86
  }
61
87
  }
62
88
 
63
- function getCurrentAnalyticsEvent() {
89
+ function _getCurrentAnalyticsEvent() {
64
90
  _validateCurrentState();
65
91
  // return a clone
66
92
  return JSON.parse(JSON.stringify(currentAnalyticsEvent));
@@ -76,10 +102,10 @@ function init() {
76
102
  }
77
103
 
78
104
  function _getOrCreateSessionID() {
79
- let localSessionID = sessionStorage.getItem(USERID_LOCAL_STORAGE_KEY);
105
+ let localSessionID = sessionStorage.getItem(SESSION_ID_LOCAL_STORAGE_KEY);
80
106
  if(!localSessionID){
81
107
  localSessionID = Math.random().toString(36).substr(2, 10);
82
- sessionStorage.setItem(USERID_LOCAL_STORAGE_KEY, localSessionID);
108
+ sessionStorage.setItem(SESSION_ID_LOCAL_STORAGE_KEY, localSessionID);
83
109
  }
84
110
  return localSessionID;
85
111
  }
@@ -98,25 +124,20 @@ function init() {
98
124
  }, DEFAULT_RETRY_TIME_IN_SECONDS * 1000 * eventToSend.backoffCount);
99
125
  }
100
126
 
101
- function _postCurrentAnalyticsEvent(eventToSend) {
102
- if(disabled){
103
- return;
104
- }
105
- if(!eventToSend){
106
- eventToSend = currentAnalyticsEvent;
107
- currentQuantisedTime = 0;
108
- _resetGranularityTimer();
109
- currentAnalyticsEvent = _createAnalyticsEvent();
110
- }
111
- if(eventToSend.numEventsTotal === 0 ){
112
- return;
113
- }
127
+ function _postEventWithRetry(eventToSend) {
114
128
  let textToSend = JSON.stringify(eventToSend);
115
129
  if(textToSend.length > POST_LARGE_DATA_THRESHOLD_BYTES){
116
130
  console.warn(`Analytics event generated is very large at greater than ${textToSend.length}B. This
117
131
  typically means that you may be sending too many value events? .`);
118
132
  }
119
133
  debugLog("Sending Analytics data of length: ", textToSend.length, "B");
134
+ debugInfo("Sending data:", textToSend);
135
+ if(!window.navigator.onLine){
136
+ _retryPost(eventToSend);
137
+ // chrome shows all network failure requests in console. In offline mode, we don't want to bomb debug
138
+ // console with network failure messages for analytics. So we prevent network requests when offline.
139
+ return;
140
+ }
120
141
  window.fetch(postURL, {
121
142
  method: "POST",
122
143
  headers: {'Content-Type': 'application/json'},
@@ -128,8 +149,7 @@ function init() {
128
149
  if(res.status !== 400){ // we don't retry bad requests
129
150
  _retryPost(eventToSend);
130
151
  } else {
131
- console.error("Analytics client: " +
132
- "Bad Request, this is most likely a problem with the library, update to latest version.");
152
+ console.error("Bad Request, this is most likely a problem with the library, update to latest version.");
133
153
  }
134
154
  }).catch(res => {
135
155
  debugError(res);
@@ -137,6 +157,22 @@ function init() {
137
157
  });
138
158
  }
139
159
 
160
+ function _postCurrentAnalyticsEvent(eventToSend) {
161
+ if(disabled){
162
+ return;
163
+ }
164
+ if(!eventToSend){
165
+ eventToSend = currentAnalyticsEvent;
166
+ currentQuantisedTime = 0;
167
+ _resetGranularityTimer();
168
+ currentAnalyticsEvent = _createAnalyticsEvent();
169
+ }
170
+ if(eventToSend.numEventsTotal === 0 ){
171
+ return;
172
+ }
173
+ _postEventWithRetry(eventToSend);
174
+ }
175
+
140
176
  function _resetGranularityTimer(disable) {
141
177
  if(granularityTimer){
142
178
  clearInterval(granularityTimer);
@@ -163,7 +199,13 @@ function init() {
163
199
  }
164
200
 
165
201
  async function _getServerConfig() {
166
- return new Promise((resolve, reject)=>{
202
+ return new Promise((resolve)=>{
203
+ if(!window.navigator.onLine){
204
+ resolve({});
205
+ // chrome shows all network failure requests in console. In offline mode, we don't want to bomb debug
206
+ // console with network failure messages for analytics. So we prevent network requests when offline.
207
+ return;
208
+ }
167
209
  let configURL = analyticsURL + `/getAppConfig?accountID=${accountID}&appName=${appName}`;
168
210
  window.fetch(configURL).then(async res=>{
169
211
  switch (res.status) {
@@ -172,13 +214,16 @@ function init() {
172
214
  resolve(serverResponse);
173
215
  return;
174
216
  case 400:
175
- reject("Bad Request, check library version compatible?", res);
217
+ debugError("Bad Request, check library version compatible?", res);
218
+ resolve({});
176
219
  break;
177
220
  default:
178
- reject("analytics client: Could not update from remote config. Continuing with defaults.", res);
221
+ debugError("Could not update from remote config. Continuing with defaults.", res);
222
+ resolve({});
179
223
  }
180
224
  }).catch(err => {
181
- reject("analytics client: Could not update from remote config. Continuing with defaults.", err);
225
+ debugError("Could not update from remote config. Continuing with defaults.", err);
226
+ resolve({});
182
227
  });
183
228
  });
184
229
  }
@@ -187,7 +232,7 @@ function init() {
187
232
  * Returns the analytics config for the app
188
233
  * @returns {Object}
189
234
  */
190
- function getAppConfig() {
235
+ function _getAppConfig() {
191
236
  return {
192
237
  accountID, appName, disabled,
193
238
  uuid: userID, sessionID,
@@ -195,13 +240,13 @@ function init() {
195
240
  };
196
241
  }
197
242
 
198
- async function _initFromRemoteConfig(postIntervalSecondsInit, granularitySecInit) {
243
+ async function _initFromRemoteConfig(postIntervalSecondsInitial, granularitySecInitial) {
199
244
  serverConfig = await _getServerConfig();
200
245
  if(serverConfig !== {}){
201
246
  // User init overrides takes precedence over server overrides
202
- postIntervalSeconds = postIntervalSecondsInit ||
247
+ postIntervalSeconds = postIntervalSecondsInitial ||
203
248
  serverConfig["postIntervalSecondsInit"] || DEFAULT_POST_INTERVAL_SECONDS;
204
- granularitySec = granularitySecInit || serverConfig["granularitySecInit"] || DEFAULT_GRANULARITY_IN_SECONDS;
249
+ granularitySec = granularitySecInitial || serverConfig["granularitySecInit"] || DEFAULT_GRANULARITY_IN_SECONDS;
205
250
  // For URLs, the server suggested URL takes precedence over user init values
206
251
  analyticsURL = serverConfig["analyticsURLInit"] || analyticsURL || DEFAULT_BASE_URL;
207
252
  disabled = serverConfig["disabled"] === true;
@@ -218,35 +263,6 @@ function init() {
218
263
  return url.replace(/\/$/, "");
219
264
  }
220
265
 
221
- /**
222
- * Initialize the analytics session
223
- * @param accountIDInit Your analytics account id as configured in the server or core.ai analytics
224
- * @param appNameInit The app name to log the events against.
225
- * @param analyticsURLInit Optional: Provide your own analytics server address if you self-hosted the server
226
- * @param postIntervalSecondsInit Optional: This defines the interval between sending analytics events to the server.
227
- * Default is 10 minutes
228
- * @param granularitySecInit Optional: The smallest time period under which the events can be distinguished. Multiple
229
- * events happening during this time period is aggregated to a count. The default granularity is 3 Seconds, which means
230
- * that any events that happen within 3 seconds cannot be distinguished in ordering.
231
- * @param debug set to true if you want to see detailed debug logs.
232
- */
233
- function initSession(accountIDInit, appNameInit, analyticsURLInit, postIntervalSecondsInit, granularitySecInit, debug) {
234
- if(!accountIDInit || !appNameInit){
235
- throw new Error("accountID and appName must exist for init");
236
- }
237
- analyticsURL = analyticsURLInit? _stripTrailingSlash(analyticsURLInit) : DEFAULT_BASE_URL;
238
- accountID = accountIDInit;
239
- appName = appNameInit;
240
- debugMode = debug || false;
241
- postIntervalSeconds = postIntervalSecondsInit || DEFAULT_POST_INTERVAL_SECONDS;
242
- granularitySec = granularitySecInit || DEFAULT_GRANULARITY_IN_SECONDS;
243
- postURL = analyticsURL + "/ingest";
244
- _setupIDs();
245
- currentAnalyticsEvent = _createAnalyticsEvent();
246
- _setupTimers();
247
- _initFromRemoteConfig(postIntervalSecondsInit, granularitySecInit);
248
- }
249
-
250
266
  function _ensureAnalyticsEventExists(eventType, category, subCategory) {
251
267
  let events = currentAnalyticsEvent.events;
252
268
  events[eventType] = events[eventType] || {};
@@ -263,10 +279,10 @@ function init() {
263
279
  throw new Error("missing eventType or category or subCategory");
264
280
  }
265
281
  if(typeof(count)!== 'number' || count <0){
266
- throw new Error("invalid count");
282
+ throw new Error("invalid count, count should be a positive number");
267
283
  }
268
284
  if(typeof(value)!== 'number'){
269
- throw new Error("invalid value");
285
+ throw new Error("invalid value, value should be a number");
270
286
  }
271
287
  }
272
288
 
@@ -321,10 +337,35 @@ function init() {
321
337
  _updateExistingAnalyticsEvent(modificationIndex, eventType, eventCategory, subCategory, eventCount, eventValue);
322
338
  }
323
339
 
324
- analytics.initSession = initSession;
325
- analytics.getCurrentAnalyticsEvent = getCurrentAnalyticsEvent;
340
+ // Init Analytics
341
+ if(!accountIDInit || !appNameInit){
342
+ throw new Error("accountID and appName must exist for init");
343
+ }
344
+ analyticsURL = analyticsURLInit? _stripTrailingSlash(analyticsURLInit) : DEFAULT_BASE_URL;
345
+ accountID = accountIDInit;
346
+ appName = appNameInit;
347
+ debugMode = debug || false;
348
+ postIntervalSeconds = postIntervalSecondsInit || DEFAULT_POST_INTERVAL_SECONDS;
349
+ granularitySec = granularitySecInit || DEFAULT_GRANULARITY_IN_SECONDS;
350
+ postURL = analyticsURL + "/ingest";
351
+ _setupIDs();
352
+ currentAnalyticsEvent = _createAnalyticsEvent();
353
+ _setupTimers();
354
+ _initFromRemoteConfig(postIntervalSecondsInit, granularitySecInit);
355
+
356
+ // As analytics lib load is async, our loading scripts will push event data into initData array till the lib load
357
+ // is complete. Now as load is done, we need to push these pending analytics events. Assuming that the async load of
358
+ // the lib should mostly happen under a second, we should not lose any accuracy of event times within the initial
359
+ // 3-second granularity. For more precision use cases, load the lib sync.
360
+ for(let eventData of analytics._initData){
361
+ event(...eventData);
362
+ }
363
+ analytics._initData = [];
364
+
365
+ // Private API for tests
366
+ analytics._getCurrentAnalyticsEvent = _getCurrentAnalyticsEvent;
367
+ analytics._getAppConfig = _getAppConfig;
368
+
369
+ // Public API
326
370
  analytics.event = event;
327
- analytics.getAppConfig = getAppConfig;
328
371
  }
329
-
330
- init();