@newrelic/browser-agent 1.305.0-rc.3 → 1.305.0-rc.5
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/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/constants/runtime.js +1 -1
- package/dist/cjs/common/session/session-entity.js +1 -0
- package/dist/cjs/common/vitals/time-to-first-byte.js +1 -0
- package/dist/cjs/common/wrap/wrap-logger.js +3 -1
- package/dist/cjs/features/logging/aggregate/index.js +42 -27
- package/dist/cjs/features/logging/instrument/index.js +3 -2
- package/dist/cjs/features/logging/shared/utils.js +3 -2
- package/dist/cjs/loaders/api/log.js +1 -1
- package/dist/cjs/loaders/api/wrapLogger.js +1 -1
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/constants/runtime.js +1 -1
- package/dist/esm/common/session/session-entity.js +1 -0
- package/dist/esm/common/vitals/time-to-first-byte.js +1 -0
- package/dist/esm/common/wrap/wrap-logger.js +3 -1
- package/dist/esm/features/logging/aggregate/index.js +42 -27
- package/dist/esm/features/logging/instrument/index.js +3 -2
- package/dist/esm/features/logging/shared/utils.js +3 -2
- package/dist/esm/loaders/api/log.js +1 -1
- package/dist/esm/loaders/api/wrapLogger.js +1 -1
- package/dist/types/common/constants/runtime.d.ts +1 -1
- package/dist/types/common/constants/runtime.d.ts.map +1 -1
- package/dist/types/common/session/session-entity.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-logger.d.ts +2 -1
- package/dist/types/common/wrap/wrap-logger.d.ts.map +1 -1
- package/dist/types/features/logging/aggregate/index.d.ts +6 -5
- package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/logging/shared/utils.d.ts +2 -1
- package/dist/types/features/logging/shared/utils.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/common/constants/runtime.js +1 -1
- package/src/common/session/session-entity.js +1 -0
- package/src/common/vitals/time-to-first-byte.js +1 -0
- package/src/common/wrap/wrap-logger.js +3 -1
- package/src/features/logging/aggregate/index.js +39 -30
- package/src/features/logging/instrument/index.js +2 -2
- package/src/features/logging/shared/utils.js +3 -2
- package/src/loaders/api/log.js +1 -1
- package/src/loaders/api/wrapLogger.js +1 -1
|
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the version of the agent
|
|
19
19
|
*/
|
|
20
|
-
const VERSION = exports.VERSION = "1.305.0-rc.
|
|
20
|
+
const VERSION = exports.VERSION = "1.305.0-rc.5";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the version of the agent
|
|
19
19
|
*/
|
|
20
|
-
const VERSION = exports.VERSION = "1.305.0-rc.
|
|
20
|
+
const VERSION = exports.VERSION = "1.305.0-rc.5";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -54,5 +54,5 @@ const ffVersion = exports.ffVersion = (() => {
|
|
|
54
54
|
* @type {number}
|
|
55
55
|
*/
|
|
56
56
|
const originTime = exports.originTime = Date.now() - (0, _now.now)();
|
|
57
|
-
const supportsNavTimingL2 = () => typeof PerformanceNavigationTiming !== 'undefined' && globalScope?.performance?.getEntriesByType('navigation')?.
|
|
57
|
+
const supportsNavTimingL2 = () => typeof PerformanceNavigationTiming !== 'undefined' && globalScope?.performance?.getEntriesByType('navigation')?.[0]?.responseStart;
|
|
58
58
|
exports.supportsNavTimingL2 = supportsNavTimingL2;
|
|
@@ -36,6 +36,7 @@ const model = {
|
|
|
36
36
|
sessionTraceMode: _constants.MODE.OFF,
|
|
37
37
|
traceHarvestStarted: false,
|
|
38
38
|
loggingMode: _constants3.LOGGING_MODE.OFF,
|
|
39
|
+
logApiMode: _constants3.LOGGING_MODE.OFF,
|
|
39
40
|
serverTimeDiff: null,
|
|
40
41
|
// set by TimeKeeper; "undefined" value will not be stringified and stored but "null" will
|
|
41
42
|
custom: {},
|
|
@@ -21,6 +21,7 @@ const timeToFirstByte = exports.timeToFirstByte = new _vitalMetric.VitalMetric(_
|
|
|
21
21
|
* - in browsers that do not support PerformanceNavigationTiming API
|
|
22
22
|
* - in an iOS browser
|
|
23
23
|
* - cross-origin iframes specifically in firefox and safari
|
|
24
|
+
* - onTTFB relies on a truthy `responseStart` value, should ensure that exists before relying on it (seen to be falsy in certain Electron.js cases for instance)
|
|
24
25
|
*/
|
|
25
26
|
if (_runtime.isBrowserScope && (0, _runtime.supportsNavTimingL2)() && !_runtime.isiOS && window === window.parent) {
|
|
26
27
|
(0, _attribution.onTTFB)(({
|
|
@@ -26,10 +26,11 @@ const contextMap = new Map();
|
|
|
26
26
|
* @param {Object} sharedEE - The shared event emitter on which a new scoped event emitter will be based.
|
|
27
27
|
* @param {Object} parent - The parent object housing the logger function
|
|
28
28
|
* @param {string} loggerFn - The name of the function in the parent object to wrap
|
|
29
|
+
* @param {boolean} [autoCaptured=true] - True if log was captured from auto wrapping. False if it was captured from the API manual usage.
|
|
29
30
|
* @returns {Object} Scoped event emitter with a debug ID of `logger`.
|
|
30
31
|
*/
|
|
31
32
|
// eslint-disable-next-line
|
|
32
|
-
function wrapLogger(sharedEE, parent, loggerFn, context) {
|
|
33
|
+
function wrapLogger(sharedEE, parent, loggerFn, context, autoCaptured = true) {
|
|
33
34
|
if (!(typeof parent === 'object' && !!parent && typeof loggerFn === 'string' && !!loggerFn && typeof parent[loggerFn] === 'function')) return (0, _console.warn)(29);
|
|
34
35
|
const ee = scopedEE(sharedEE);
|
|
35
36
|
const wrapFn = (0, _wrapFunction.createWrapperWithEmitter)(ee);
|
|
@@ -41,6 +42,7 @@ function wrapLogger(sharedEE, parent, loggerFn, context) {
|
|
|
41
42
|
const ctx = new _eventContext.EventContext(_contextualEe.contextId);
|
|
42
43
|
ctx.level = context.level;
|
|
43
44
|
ctx.customAttributes = context.customAttributes;
|
|
45
|
+
ctx.autoCaptured = autoCaptured;
|
|
44
46
|
const contextLookupKey = parent[loggerFn]?.[_wrapFunction.flag] || parent[loggerFn];
|
|
45
47
|
contextMap.set(contextLookupKey, ctx);
|
|
46
48
|
|
|
@@ -21,11 +21,19 @@ var _mfe = require("../../../common/util/mfe");
|
|
|
21
21
|
* SPDX-License-Identifier: Apache-2.0
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
+
const LOGGING_EVENT = 'Logging/Event/';
|
|
24
25
|
class Aggregate extends _aggregateBase.AggregateBase {
|
|
25
26
|
static featureName = _constants.FEATURE_NAME;
|
|
26
27
|
constructor(agentRef) {
|
|
27
28
|
super(agentRef, _constants.FEATURE_NAME);
|
|
28
|
-
|
|
29
|
+
const updateLocalLoggingMode = (auto, api) => {
|
|
30
|
+
this.loggingMode = {
|
|
31
|
+
auto,
|
|
32
|
+
api
|
|
33
|
+
};
|
|
34
|
+
// In agent v1.290.0 & under, the logApiMode prop did not yet exist, so need to account for old session state being in-use.
|
|
35
|
+
if (api === undefined) this.loggingMode.api = auto;
|
|
36
|
+
};
|
|
29
37
|
|
|
30
38
|
/** set up agg-level behaviors specific to this feature */
|
|
31
39
|
this.harvestOpts.raw = true;
|
|
@@ -37,20 +45,25 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
37
45
|
});
|
|
38
46
|
this.ee.on(_constants2.SESSION_EVENTS.UPDATE, (type, data) => {
|
|
39
47
|
if (this.blocked || type !== _constants2.SESSION_EVENT_TYPES.CROSS_TAB) return;
|
|
40
|
-
|
|
48
|
+
// In agent v1.290.0 & under, the logApiMode prop did not yet exist, so need to account for old session state being in-use with just loggingMode off == feature off.
|
|
49
|
+
if (data.loggingMode === _constants.LOGGING_MODE.OFF && (!data.logApiMode || data.logApiMode === _constants.LOGGING_MODE.OFF)) this.abort(_constants3.ABORT_REASONS.CROSS_TAB);else updateLocalLoggingMode(data.loggingMode, data.logApiMode);
|
|
41
50
|
});
|
|
42
|
-
this.waitForFlags(['log']).then(([
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
this.waitForFlags(['log', 'logapi']).then(([auto, api]) => {
|
|
52
|
+
if (this.blocked) return; // means abort already happened before this, likely from session reset or update; abort would've set mode off + deregistered drain
|
|
53
|
+
|
|
54
|
+
this.loggingMode ??= {
|
|
55
|
+
auto,
|
|
56
|
+
api
|
|
57
|
+
}; // likewise, don't want to overwrite the mode if it was set already
|
|
58
|
+
const session = this.agentRef.runtime.session;
|
|
59
|
+
if ((0, _featureGates.canEnableSessionTracking)(agentRef.init) && session) {
|
|
60
|
+
if (session.isNew) this.#syncWithSessionManager();else updateLocalLoggingMode(session.state.loggingMode, session.state.logApiMode);
|
|
61
|
+
}
|
|
62
|
+
if (this.loggingMode.auto === _constants.LOGGING_MODE.OFF && this.loggingMode.api === _constants.LOGGING_MODE.OFF) {
|
|
45
63
|
this.blocked = true;
|
|
46
64
|
this.deregisterDrain();
|
|
47
65
|
return;
|
|
48
66
|
}
|
|
49
|
-
if (session.isNew || !this.isSessionTrackingEnabled) {
|
|
50
|
-
this.updateLoggingMode(loggingMode);
|
|
51
|
-
} else {
|
|
52
|
-
this.loggingMode = session.state.loggingMode;
|
|
53
|
-
}
|
|
54
67
|
|
|
55
68
|
/** emitted by instrument class (wrapped loggers) or the api methods directly */
|
|
56
69
|
(0, _registerHandler.registerHandler)(_constants.LOGGING_EVENT_EMITTER_CHANNEL, this.handleLog.bind(this), this.featureName, this.ee);
|
|
@@ -59,14 +72,11 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
59
72
|
agentRef.runtime.harvester.triggerHarvestFor(this);
|
|
60
73
|
});
|
|
61
74
|
}
|
|
62
|
-
|
|
63
|
-
this.
|
|
64
|
-
this.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
handleLog(timestamp, message, attributes = {}, level = _constants.LOG_LEVELS.INFO, target) {
|
|
69
|
-
if (this.blocked || !this.loggingMode) return;
|
|
75
|
+
handleLog(timestamp, message, attributes = {}, level = _constants.LOG_LEVELS.INFO, autoCaptured, target) {
|
|
76
|
+
if (this.blocked) return;
|
|
77
|
+
// Check respective logging mode depending on whether this log is from auto wrapped instrumentation or manual API that it's not turned off.
|
|
78
|
+
const modeForThisLog = autoCaptured ? this.loggingMode.auto : this.loggingMode.api;
|
|
79
|
+
if (!modeForThisLog) return;
|
|
70
80
|
if (!attributes || typeof attributes !== 'object') attributes = {};
|
|
71
81
|
attributes = {
|
|
72
82
|
...attributes,
|
|
@@ -75,8 +85,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
75
85
|
};
|
|
76
86
|
if (typeof level === 'string') level = level.toUpperCase();
|
|
77
87
|
if (!(0, _utils.isValidLogLevel)(level)) return (0, _console.warn)(30, level);
|
|
78
|
-
if (
|
|
79
|
-
this.reportSupportabilityMetric('
|
|
88
|
+
if (modeForThisLog < (_constants.LOGGING_MODE[level] || Infinity)) {
|
|
89
|
+
this.reportSupportabilityMetric(LOGGING_EVENT + 'Dropped/Sampling');
|
|
80
90
|
return;
|
|
81
91
|
}
|
|
82
92
|
try {
|
|
@@ -91,12 +101,12 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
91
101
|
}
|
|
92
102
|
} catch (err) {
|
|
93
103
|
(0, _console.warn)(16, message);
|
|
94
|
-
this.reportSupportabilityMetric('
|
|
104
|
+
this.reportSupportabilityMetric(LOGGING_EVENT + 'Dropped/Casting');
|
|
95
105
|
return;
|
|
96
106
|
}
|
|
97
107
|
if (typeof message !== 'string' || !message) return (0, _console.warn)(32);
|
|
98
108
|
const log = new _log.Log(Math.floor(this.agentRef.runtime.timeKeeper.correctRelativeTimestamp(timestamp)), message, attributes, level);
|
|
99
|
-
this.events.add(log);
|
|
109
|
+
if (this.events.add(log)) this.reportSupportabilityMetric(LOGGING_EVENT + (autoCaptured ? 'Auto' : 'API') + '/Added');
|
|
100
110
|
}
|
|
101
111
|
serializer(eventBuffer) {
|
|
102
112
|
const sessionEntity = this.agentRef.runtime.session;
|
|
@@ -146,13 +156,18 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
146
156
|
this.events.clear();
|
|
147
157
|
this.events.clearSave();
|
|
148
158
|
}
|
|
149
|
-
this.
|
|
159
|
+
this.loggingMode = {
|
|
160
|
+
auto: _constants.LOGGING_MODE.OFF,
|
|
161
|
+
api: _constants.LOGGING_MODE.OFF
|
|
162
|
+
};
|
|
163
|
+
this.#syncWithSessionManager();
|
|
150
164
|
this.deregisterDrain();
|
|
151
165
|
}
|
|
152
|
-
syncWithSessionManager(
|
|
153
|
-
|
|
154
|
-
this.
|
|
155
|
-
|
|
166
|
+
#syncWithSessionManager() {
|
|
167
|
+
this.agentRef.runtime.session?.write({
|
|
168
|
+
loggingMode: this.loggingMode.auto,
|
|
169
|
+
logApiMode: this.loggingMode.api
|
|
170
|
+
});
|
|
156
171
|
}
|
|
157
172
|
}
|
|
158
173
|
exports.Aggregate = Aggregate;
|
|
@@ -39,9 +39,10 @@ class Instrument extends _instrumentBase.InstrumentBase {
|
|
|
39
39
|
this.ee.on('wrap-logger-end', function handleLog([message]) {
|
|
40
40
|
const {
|
|
41
41
|
level,
|
|
42
|
-
customAttributes
|
|
42
|
+
customAttributes,
|
|
43
|
+
autoCaptured
|
|
43
44
|
} = this;
|
|
44
|
-
(0, _utils.bufferLog)(instanceEE, message, customAttributes, level);
|
|
45
|
+
(0, _utils.bufferLog)(instanceEE, message, customAttributes, level, autoCaptured);
|
|
45
46
|
});
|
|
46
47
|
this.importAggregator(agentRef, () => Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "logging-aggregate" */'../aggregate'))));
|
|
47
48
|
}
|
|
@@ -20,11 +20,12 @@ var _constants2 = require("../constants");
|
|
|
20
20
|
* @param {string} message - the log message string
|
|
21
21
|
* @param {{[key: string]: *}} customAttributes - The log's custom attributes if any
|
|
22
22
|
* @param {enum} level - the log level enum
|
|
23
|
+
* @param {boolean} [autoCaptured=true] - True if log was captured from auto wrapping. False if it was captured from the API manual usage.
|
|
23
24
|
* @param {object=} target - the optional target provided by an api call
|
|
24
25
|
*/
|
|
25
|
-
function bufferLog(ee, message, customAttributes = {}, level = _constants2.LOG_LEVELS.INFO, target, timestamp = (0, _now.now)()) {
|
|
26
|
+
function bufferLog(ee, message, customAttributes = {}, level = _constants2.LOG_LEVELS.INFO, autoCaptured = true, target, timestamp = (0, _now.now)()) {
|
|
26
27
|
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ["API/logging/".concat(level.toLowerCase(), "/called")], undefined, _features.FEATURE_NAMES.metrics, ee);
|
|
27
|
-
(0, _handle.handle)(_constants2.LOGGING_EVENT_EMITTER_CHANNEL, [timestamp, message, customAttributes, level, target], undefined, _features.FEATURE_NAMES.logging, ee);
|
|
28
|
+
(0, _handle.handle)(_constants2.LOGGING_EVENT_EMITTER_CHANNEL, [timestamp, message, customAttributes, level, autoCaptured, target], undefined, _features.FEATURE_NAMES.logging, ee);
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
/**
|
|
@@ -22,5 +22,5 @@ function log(message, {
|
|
|
22
22
|
customAttributes = {},
|
|
23
23
|
level = _constants.LOG_LEVELS.INFO
|
|
24
24
|
} = {}, agentRef, target, timestamp = (0, _now.now)()) {
|
|
25
|
-
(0, _utils.bufferLog)(agentRef.ee, message, customAttributes, level, target, timestamp);
|
|
25
|
+
(0, _utils.bufferLog)(agentRef.ee, message, customAttributes, level, false, target, timestamp);
|
|
26
26
|
}
|
|
@@ -49,4 +49,4 @@ export const ffVersion = (() => {
|
|
|
49
49
|
* @type {number}
|
|
50
50
|
*/
|
|
51
51
|
export const originTime = Date.now() - now();
|
|
52
|
-
export const supportsNavTimingL2 = () => typeof PerformanceNavigationTiming !== 'undefined' && globalScope?.performance?.getEntriesByType('navigation')?.
|
|
52
|
+
export const supportsNavTimingL2 = () => typeof PerformanceNavigationTiming !== 'undefined' && globalScope?.performance?.getEntriesByType('navigation')?.[0]?.responseStart;
|
|
@@ -30,6 +30,7 @@ const model = {
|
|
|
30
30
|
sessionTraceMode: MODE.OFF,
|
|
31
31
|
traceHarvestStarted: false,
|
|
32
32
|
loggingMode: LOGGING_MODE.OFF,
|
|
33
|
+
logApiMode: LOGGING_MODE.OFF,
|
|
33
34
|
serverTimeDiff: null,
|
|
34
35
|
// set by TimeKeeper; "undefined" value will not be stringified and stored but "null" will
|
|
35
36
|
custom: {},
|
|
@@ -14,6 +14,7 @@ export const timeToFirstByte = new VitalMetric(VITAL_NAMES.TIME_TO_FIRST_BYTE);
|
|
|
14
14
|
* - in browsers that do not support PerformanceNavigationTiming API
|
|
15
15
|
* - in an iOS browser
|
|
16
16
|
* - cross-origin iframes specifically in firefox and safari
|
|
17
|
+
* - onTTFB relies on a truthy `responseStart` value, should ensure that exists before relying on it (seen to be falsy in certain Electron.js cases for instance)
|
|
17
18
|
*/
|
|
18
19
|
if (isBrowserScope && supportsNavTimingL2() && !isiOS && window === window.parent) {
|
|
19
20
|
onTTFB(({
|
|
@@ -19,10 +19,11 @@ const contextMap = new Map();
|
|
|
19
19
|
* @param {Object} sharedEE - The shared event emitter on which a new scoped event emitter will be based.
|
|
20
20
|
* @param {Object} parent - The parent object housing the logger function
|
|
21
21
|
* @param {string} loggerFn - The name of the function in the parent object to wrap
|
|
22
|
+
* @param {boolean} [autoCaptured=true] - True if log was captured from auto wrapping. False if it was captured from the API manual usage.
|
|
22
23
|
* @returns {Object} Scoped event emitter with a debug ID of `logger`.
|
|
23
24
|
*/
|
|
24
25
|
// eslint-disable-next-line
|
|
25
|
-
export function wrapLogger(sharedEE, parent, loggerFn, context) {
|
|
26
|
+
export function wrapLogger(sharedEE, parent, loggerFn, context, autoCaptured = true) {
|
|
26
27
|
if (!(typeof parent === 'object' && !!parent && typeof loggerFn === 'string' && !!loggerFn && typeof parent[loggerFn] === 'function')) return warn(29);
|
|
27
28
|
const ee = scopedEE(sharedEE);
|
|
28
29
|
const wrapFn = wfn(ee);
|
|
@@ -34,6 +35,7 @@ export function wrapLogger(sharedEE, parent, loggerFn, context) {
|
|
|
34
35
|
const ctx = new EventContext(contextId);
|
|
35
36
|
ctx.level = context.level;
|
|
36
37
|
ctx.customAttributes = context.customAttributes;
|
|
38
|
+
ctx.autoCaptured = autoCaptured;
|
|
37
39
|
const contextLookupKey = parent[loggerFn]?.[flag] || parent[loggerFn];
|
|
38
40
|
contextMap.set(contextLookupKey, ctx);
|
|
39
41
|
|
|
@@ -14,11 +14,19 @@ import { SESSION_EVENT_TYPES, SESSION_EVENTS } from '../../../common/session/con
|
|
|
14
14
|
import { ABORT_REASONS } from '../../session_replay/constants';
|
|
15
15
|
import { canEnableSessionTracking } from '../../utils/feature-gates';
|
|
16
16
|
import { getVersion2Attributes } from '../../../common/util/mfe';
|
|
17
|
+
const LOGGING_EVENT = 'Logging/Event/';
|
|
17
18
|
export class Aggregate extends AggregateBase {
|
|
18
19
|
static featureName = FEATURE_NAME;
|
|
19
20
|
constructor(agentRef) {
|
|
20
21
|
super(agentRef, FEATURE_NAME);
|
|
21
|
-
|
|
22
|
+
const updateLocalLoggingMode = (auto, api) => {
|
|
23
|
+
this.loggingMode = {
|
|
24
|
+
auto,
|
|
25
|
+
api
|
|
26
|
+
};
|
|
27
|
+
// In agent v1.290.0 & under, the logApiMode prop did not yet exist, so need to account for old session state being in-use.
|
|
28
|
+
if (api === undefined) this.loggingMode.api = auto;
|
|
29
|
+
};
|
|
22
30
|
|
|
23
31
|
/** set up agg-level behaviors specific to this feature */
|
|
24
32
|
this.harvestOpts.raw = true;
|
|
@@ -30,20 +38,25 @@ export class Aggregate extends AggregateBase {
|
|
|
30
38
|
});
|
|
31
39
|
this.ee.on(SESSION_EVENTS.UPDATE, (type, data) => {
|
|
32
40
|
if (this.blocked || type !== SESSION_EVENT_TYPES.CROSS_TAB) return;
|
|
33
|
-
|
|
41
|
+
// In agent v1.290.0 & under, the logApiMode prop did not yet exist, so need to account for old session state being in-use with just loggingMode off == feature off.
|
|
42
|
+
if (data.loggingMode === LOGGING_MODE.OFF && (!data.logApiMode || data.logApiMode === LOGGING_MODE.OFF)) this.abort(ABORT_REASONS.CROSS_TAB);else updateLocalLoggingMode(data.loggingMode, data.logApiMode);
|
|
34
43
|
});
|
|
35
|
-
this.waitForFlags(['log']).then(([
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
this.waitForFlags(['log', 'logapi']).then(([auto, api]) => {
|
|
45
|
+
if (this.blocked) return; // means abort already happened before this, likely from session reset or update; abort would've set mode off + deregistered drain
|
|
46
|
+
|
|
47
|
+
this.loggingMode ??= {
|
|
48
|
+
auto,
|
|
49
|
+
api
|
|
50
|
+
}; // likewise, don't want to overwrite the mode if it was set already
|
|
51
|
+
const session = this.agentRef.runtime.session;
|
|
52
|
+
if (canEnableSessionTracking(agentRef.init) && session) {
|
|
53
|
+
if (session.isNew) this.#syncWithSessionManager();else updateLocalLoggingMode(session.state.loggingMode, session.state.logApiMode);
|
|
54
|
+
}
|
|
55
|
+
if (this.loggingMode.auto === LOGGING_MODE.OFF && this.loggingMode.api === LOGGING_MODE.OFF) {
|
|
38
56
|
this.blocked = true;
|
|
39
57
|
this.deregisterDrain();
|
|
40
58
|
return;
|
|
41
59
|
}
|
|
42
|
-
if (session.isNew || !this.isSessionTrackingEnabled) {
|
|
43
|
-
this.updateLoggingMode(loggingMode);
|
|
44
|
-
} else {
|
|
45
|
-
this.loggingMode = session.state.loggingMode;
|
|
46
|
-
}
|
|
47
60
|
|
|
48
61
|
/** emitted by instrument class (wrapped loggers) or the api methods directly */
|
|
49
62
|
registerHandler(LOGGING_EVENT_EMITTER_CHANNEL, this.handleLog.bind(this), this.featureName, this.ee);
|
|
@@ -52,14 +65,11 @@ export class Aggregate extends AggregateBase {
|
|
|
52
65
|
agentRef.runtime.harvester.triggerHarvestFor(this);
|
|
53
66
|
});
|
|
54
67
|
}
|
|
55
|
-
|
|
56
|
-
this.
|
|
57
|
-
this.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
handleLog(timestamp, message, attributes = {}, level = LOG_LEVELS.INFO, target) {
|
|
62
|
-
if (this.blocked || !this.loggingMode) return;
|
|
68
|
+
handleLog(timestamp, message, attributes = {}, level = LOG_LEVELS.INFO, autoCaptured, target) {
|
|
69
|
+
if (this.blocked) return;
|
|
70
|
+
// Check respective logging mode depending on whether this log is from auto wrapped instrumentation or manual API that it's not turned off.
|
|
71
|
+
const modeForThisLog = autoCaptured ? this.loggingMode.auto : this.loggingMode.api;
|
|
72
|
+
if (!modeForThisLog) return;
|
|
63
73
|
if (!attributes || typeof attributes !== 'object') attributes = {};
|
|
64
74
|
attributes = {
|
|
65
75
|
...attributes,
|
|
@@ -68,8 +78,8 @@ export class Aggregate extends AggregateBase {
|
|
|
68
78
|
};
|
|
69
79
|
if (typeof level === 'string') level = level.toUpperCase();
|
|
70
80
|
if (!isValidLogLevel(level)) return warn(30, level);
|
|
71
|
-
if (
|
|
72
|
-
this.reportSupportabilityMetric('
|
|
81
|
+
if (modeForThisLog < (LOGGING_MODE[level] || Infinity)) {
|
|
82
|
+
this.reportSupportabilityMetric(LOGGING_EVENT + 'Dropped/Sampling');
|
|
73
83
|
return;
|
|
74
84
|
}
|
|
75
85
|
try {
|
|
@@ -84,12 +94,12 @@ export class Aggregate extends AggregateBase {
|
|
|
84
94
|
}
|
|
85
95
|
} catch (err) {
|
|
86
96
|
warn(16, message);
|
|
87
|
-
this.reportSupportabilityMetric('
|
|
97
|
+
this.reportSupportabilityMetric(LOGGING_EVENT + 'Dropped/Casting');
|
|
88
98
|
return;
|
|
89
99
|
}
|
|
90
100
|
if (typeof message !== 'string' || !message) return warn(32);
|
|
91
101
|
const log = new Log(Math.floor(this.agentRef.runtime.timeKeeper.correctRelativeTimestamp(timestamp)), message, attributes, level);
|
|
92
|
-
this.events.add(log);
|
|
102
|
+
if (this.events.add(log)) this.reportSupportabilityMetric(LOGGING_EVENT + (autoCaptured ? 'Auto' : 'API') + '/Added');
|
|
93
103
|
}
|
|
94
104
|
serializer(eventBuffer) {
|
|
95
105
|
const sessionEntity = this.agentRef.runtime.session;
|
|
@@ -139,12 +149,17 @@ export class Aggregate extends AggregateBase {
|
|
|
139
149
|
this.events.clear();
|
|
140
150
|
this.events.clearSave();
|
|
141
151
|
}
|
|
142
|
-
this.
|
|
152
|
+
this.loggingMode = {
|
|
153
|
+
auto: LOGGING_MODE.OFF,
|
|
154
|
+
api: LOGGING_MODE.OFF
|
|
155
|
+
};
|
|
156
|
+
this.#syncWithSessionManager();
|
|
143
157
|
this.deregisterDrain();
|
|
144
158
|
}
|
|
145
|
-
syncWithSessionManager(
|
|
146
|
-
|
|
147
|
-
this.
|
|
148
|
-
|
|
159
|
+
#syncWithSessionManager() {
|
|
160
|
+
this.agentRef.runtime.session?.write({
|
|
161
|
+
loggingMode: this.loggingMode.auto,
|
|
162
|
+
logApiMode: this.loggingMode.api
|
|
163
|
+
});
|
|
149
164
|
}
|
|
150
165
|
}
|
|
@@ -33,9 +33,10 @@ export class Instrument extends InstrumentBase {
|
|
|
33
33
|
this.ee.on('wrap-logger-end', function handleLog([message]) {
|
|
34
34
|
const {
|
|
35
35
|
level,
|
|
36
|
-
customAttributes
|
|
36
|
+
customAttributes,
|
|
37
|
+
autoCaptured
|
|
37
38
|
} = this;
|
|
38
|
-
bufferLog(instanceEE, message, customAttributes, level);
|
|
39
|
+
bufferLog(instanceEE, message, customAttributes, level, autoCaptured);
|
|
39
40
|
});
|
|
40
41
|
this.importAggregator(agentRef, () => import(/* webpackChunkName: "logging-aggregate" */'../aggregate'));
|
|
41
42
|
}
|
|
@@ -13,11 +13,12 @@ import { LOGGING_EVENT_EMITTER_CHANNEL, LOG_LEVELS } from '../constants';
|
|
|
13
13
|
* @param {string} message - the log message string
|
|
14
14
|
* @param {{[key: string]: *}} customAttributes - The log's custom attributes if any
|
|
15
15
|
* @param {enum} level - the log level enum
|
|
16
|
+
* @param {boolean} [autoCaptured=true] - True if log was captured from auto wrapping. False if it was captured from the API manual usage.
|
|
16
17
|
* @param {object=} target - the optional target provided by an api call
|
|
17
18
|
*/
|
|
18
|
-
export function bufferLog(ee, message, customAttributes = {}, level = LOG_LEVELS.INFO, target, timestamp = now()) {
|
|
19
|
+
export function bufferLog(ee, message, customAttributes = {}, level = LOG_LEVELS.INFO, autoCaptured = true, target, timestamp = now()) {
|
|
19
20
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ["API/logging/".concat(level.toLowerCase(), "/called")], undefined, FEATURE_NAMES.metrics, ee);
|
|
20
|
-
handle(LOGGING_EVENT_EMITTER_CHANNEL, [timestamp, message, customAttributes, level, target], undefined, FEATURE_NAMES.logging, ee);
|
|
21
|
+
handle(LOGGING_EVENT_EMITTER_CHANNEL, [timestamp, message, customAttributes, level, autoCaptured, target], undefined, FEATURE_NAMES.logging, ee);
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -15,5 +15,5 @@ export function log(message, {
|
|
|
15
15
|
customAttributes = {},
|
|
16
16
|
level = LOG_LEVELS.INFO
|
|
17
17
|
} = {}, agentRef, target, timestamp = now()) {
|
|
18
|
-
bufferLog(agentRef.ee, message, customAttributes, level, target, timestamp);
|
|
18
|
+
bufferLog(agentRef.ee, message, customAttributes, level, false, target, timestamp);
|
|
19
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/runtime.js"],"names":[],"mappings":"AAcA;;GAEG;AACH,qCAEqB;AAErB;;GAEG;AACH,oCAeK;AAEL,oDAUI;AAEJ,oDAA6F;AAE7F,sCAA2F;AAE3F,qCAAyD;AAEzD,4BAA8E;AAE9E;;;;;;GAMG;AACH,iCAAwE;AAExE,+BAOI;AAEJ;;;;GAIG;AACH,yBAFU,MAAM,CAE4B;AAErC
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/runtime.js"],"names":[],"mappings":"AAcA;;GAEG;AACH,qCAEqB;AAErB;;GAEG;AACH,oCAeK;AAEL,oDAUI;AAEJ,oDAA6F;AAE7F,sCAA2F;AAE3F,qCAAyD;AAEzD,4BAA8E;AAE9E;;;;;;GAMG;AACH,iCAAwE;AAExE,+BAOI;AAEJ;;;;GAIG;AACH,yBAFU,MAAM,CAE4B;AAErC,2CAAoK"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-entity.d.ts","sourceRoot":"","sources":["../../../../src/common/session/session-entity.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session-entity.d.ts","sourceRoot":"","sources":["../../../../src/common/session/session-entity.js"],"names":[],"mappings":"AAuCA;IACE;;;;;OAKG;IACH,uBA+BC;IAzBC,qBAAsC;IACtC,aAAsB;IACtB,UAAe;IAGf,SAAc;IAEd,QAAiC;IAoBnC;;;;;aAgFC;IApEC,8BAA0B;IAC1B,+BAA4B;IAe1B,gCAOqC;IAUrC,4CAkBsC;IAexC,iCAAuB;IAKzB,wBAEC;IAED,sBAEC;IAED;;;OAGG;IACH,QAFa,MAAM,CA6BlB;IAED;;;;;;OAMG;IACH,YAHW,MAAM,GACJ,MAAM,CAkBlB;IAED,gBA4BC;IAED;;OAEG;IACH,gBAIC;IAED;;;OAGG;IACH,qBAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;OAGG;IACH,gBAHW,MAAM,GACJ,OAAO,CAKnB;IAED,yDAUC;IAED,6DAIC;IAED;;;OAGG;IACH,6BAHW,MAAM,GACJ,MAAM,CAIlB;IAED,gDAaC;IAHG,YAAuD;CAI5D;sBA5TqB,gBAAgB;iCAGL,4BAA4B"}
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* @param {Object} sharedEE - The shared event emitter on which a new scoped event emitter will be based.
|
|
4
4
|
* @param {Object} parent - The parent object housing the logger function
|
|
5
5
|
* @param {string} loggerFn - The name of the function in the parent object to wrap
|
|
6
|
+
* @param {boolean} [autoCaptured=true] - True if log was captured from auto wrapping. False if it was captured from the API manual usage.
|
|
6
7
|
* @returns {Object} Scoped event emitter with a debug ID of `logger`.
|
|
7
8
|
*/
|
|
8
|
-
export function wrapLogger(sharedEE: Object, parent: Object, loggerFn: string, context: any): Object;
|
|
9
|
+
export function wrapLogger(sharedEE: Object, parent: Object, loggerFn: string, context: any, autoCaptured?: boolean): Object;
|
|
9
10
|
/**
|
|
10
11
|
* Returns an event emitter scoped specifically for the `logger` context. This scoping is a remnant from when all the
|
|
11
12
|
* features shared the same group in the event, to isolate events between features. It will likely be revisited.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrap-logger.d.ts","sourceRoot":"","sources":["../../../../src/common/wrap/wrap-logger.js"],"names":[],"mappings":"AAiBA
|
|
1
|
+
{"version":3,"file":"wrap-logger.d.ts","sourceRoot":"","sources":["../../../../src/common/wrap/wrap-logger.js"],"names":[],"mappings":"AAiBA;;;;;;;GAOG;AAEH,qCAPW,MAAM,UACN,MAAM,YACN,MAAM,+BACN,OAAO,GACL,MAAM,CAwBlB;AAED;;;;;;GAMG;AACH,mCAJW,MAAM,GAEJ,MAAM,CAIlB"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export class Aggregate extends AggregateBase {
|
|
2
2
|
static featureName: string;
|
|
3
3
|
constructor(agentRef: any);
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
loggingMode: {
|
|
5
|
+
auto: any;
|
|
6
|
+
api: any;
|
|
7
|
+
};
|
|
8
|
+
handleLog(timestamp: any, message: any, attributes: {} | undefined, level: string | undefined, autoCaptured: any, target: any): void;
|
|
8
9
|
serializer(eventBuffer: any): {
|
|
9
10
|
common: {
|
|
10
11
|
/** Attributes in the `common` section are added to `all` logs generated in the payload */
|
|
@@ -18,7 +19,7 @@ export class Aggregate extends AggregateBase {
|
|
|
18
19
|
};
|
|
19
20
|
/** Abort the feature, once aborted it will not resume */
|
|
20
21
|
abort(reason?: {}): void;
|
|
21
|
-
|
|
22
|
+
#private;
|
|
22
23
|
}
|
|
23
24
|
import { AggregateBase } from '../../utils/aggregate-base';
|
|
24
25
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/logging/aggregate/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/logging/aggregate/index.js"],"names":[],"mappings":"AAmBA;IACE,2BAAiC;IACjC,2BA4CC;IAzCG;;;MAAgC;IA2CpC,qIA+CC;IAED;;YAIM,0FAA0F;;;QAqB5F,0DAA0D;;QAM7D;IAED;;MAEC;IAED,yDAAyD;IACzD,yBAaC;;CAQF;8BAxK6B,4BAA4B"}
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
* @param {string} message - the log message string
|
|
4
4
|
* @param {{[key: string]: *}} customAttributes - The log's custom attributes if any
|
|
5
5
|
* @param {enum} level - the log level enum
|
|
6
|
+
* @param {boolean} [autoCaptured=true] - True if log was captured from auto wrapping. False if it was captured from the API manual usage.
|
|
6
7
|
* @param {object=} target - the optional target provided by an api call
|
|
7
8
|
*/
|
|
8
9
|
export function bufferLog(ee: ContextualEE, message: string, customAttributes?: {
|
|
9
10
|
[key: string]: any;
|
|
10
|
-
}, level?: enum, target?: object | undefined, timestamp?: number): void;
|
|
11
|
+
}, level?: enum, autoCaptured?: boolean, target?: object | undefined, timestamp?: number): void;
|
|
11
12
|
/**
|
|
12
13
|
* Checks if a supplied log level is acceptable for use in generating a log event
|
|
13
14
|
* @param {string} level -- must be cast to uppercase before running this test
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/features/logging/shared/utils.js"],"names":[],"mappings":"AAUA
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/features/logging/shared/utils.js"],"names":[],"mappings":"AAUA;;;;;;;KAOK;AACL,8BAPa,YAAY,WACZ,MAAM,qBACN;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAC,CAAA;CAAC,UAClB,IAAI,iBACJ,OAAO,WACP,MAAM,YAAC,4BAKnB;AAED;;;;GAIG;AACH,uCAHW,MAAM,GACJ,OAAO,CAKnB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newrelic/browser-agent",
|
|
3
|
-
"version": "1.305.0-rc.
|
|
3
|
+
"version": "1.305.0-rc.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
|
|
6
6
|
"description": "New Relic Browser Agent",
|
|
@@ -195,6 +195,7 @@
|
|
|
195
195
|
"build:npm": "npm run npm:build:esm && npm run npm:build:cjs && npm run npm:build:types && npm run npm:pack",
|
|
196
196
|
"cdn:build": "npm run cdn:build:prod",
|
|
197
197
|
"cdn:build:local": "npm run cdn:webpack",
|
|
198
|
+
"cdn:build:local-external": "npm run cdn:webpack -- --env mode=local-external",
|
|
198
199
|
"cdn:build:prod": "npm run cdn:webpack -- --env mode=prod",
|
|
199
200
|
"cdn:build:dev": "npm run cdn:webpack -- --env mode=dev",
|
|
200
201
|
"cdn:build:experiment": "npm run cdn:webpack -- --env mode=experiment",
|
|
@@ -84,4 +84,4 @@ export const ffVersion = (() => {
|
|
|
84
84
|
*/
|
|
85
85
|
export const originTime = Date.now() - now()
|
|
86
86
|
|
|
87
|
-
export const supportsNavTimingL2 = () => typeof PerformanceNavigationTiming !== 'undefined' && globalScope?.performance?.getEntriesByType('navigation')?.
|
|
87
|
+
export const supportsNavTimingL2 = () => typeof PerformanceNavigationTiming !== 'undefined' && globalScope?.performance?.getEntriesByType('navigation')?.[0]?.responseStart
|
|
@@ -30,6 +30,7 @@ const model = {
|
|
|
30
30
|
sessionTraceMode: MODE.OFF,
|
|
31
31
|
traceHarvestStarted: false,
|
|
32
32
|
loggingMode: LOGGING_MODE.OFF,
|
|
33
|
+
logApiMode: LOGGING_MODE.OFF,
|
|
33
34
|
serverTimeDiff: null, // set by TimeKeeper; "undefined" value will not be stringified and stored but "null" will
|
|
34
35
|
custom: {},
|
|
35
36
|
numOfResets: 0,
|
|
@@ -15,6 +15,7 @@ export const timeToFirstByte = new VitalMetric(VITAL_NAMES.TIME_TO_FIRST_BYTE)
|
|
|
15
15
|
* - in browsers that do not support PerformanceNavigationTiming API
|
|
16
16
|
* - in an iOS browser
|
|
17
17
|
* - cross-origin iframes specifically in firefox and safari
|
|
18
|
+
* - onTTFB relies on a truthy `responseStart` value, should ensure that exists before relying on it (seen to be falsy in certain Electron.js cases for instance)
|
|
18
19
|
*/
|
|
19
20
|
if (isBrowserScope && supportsNavTimingL2() && !isiOS && window === window.parent) {
|
|
20
21
|
onTTFB(({ value, attribution }) => {
|
|
@@ -20,10 +20,11 @@ const contextMap = new Map()
|
|
|
20
20
|
* @param {Object} sharedEE - The shared event emitter on which a new scoped event emitter will be based.
|
|
21
21
|
* @param {Object} parent - The parent object housing the logger function
|
|
22
22
|
* @param {string} loggerFn - The name of the function in the parent object to wrap
|
|
23
|
+
* @param {boolean} [autoCaptured=true] - True if log was captured from auto wrapping. False if it was captured from the API manual usage.
|
|
23
24
|
* @returns {Object} Scoped event emitter with a debug ID of `logger`.
|
|
24
25
|
*/
|
|
25
26
|
// eslint-disable-next-line
|
|
26
|
-
export function wrapLogger(sharedEE, parent, loggerFn, context) {
|
|
27
|
+
export function wrapLogger(sharedEE, parent, loggerFn, context, autoCaptured = true) {
|
|
27
28
|
if (!(typeof parent === 'object' && !!parent && typeof loggerFn === 'string' && !!loggerFn && typeof parent[loggerFn] === 'function')) return warn(29)
|
|
28
29
|
const ee = scopedEE(sharedEE)
|
|
29
30
|
const wrapFn = wfn(ee)
|
|
@@ -35,6 +36,7 @@ export function wrapLogger(sharedEE, parent, loggerFn, context) {
|
|
|
35
36
|
const ctx = new EventContext(contextId)
|
|
36
37
|
ctx.level = context.level
|
|
37
38
|
ctx.customAttributes = context.customAttributes
|
|
39
|
+
ctx.autoCaptured = autoCaptured
|
|
38
40
|
|
|
39
41
|
const contextLookupKey = parent[loggerFn]?.[flag] || parent[loggerFn]
|
|
40
42
|
contextMap.set(contextLookupKey, ctx)
|
|
@@ -15,11 +15,17 @@ import { ABORT_REASONS } from '../../session_replay/constants'
|
|
|
15
15
|
import { canEnableSessionTracking } from '../../utils/feature-gates'
|
|
16
16
|
import { getVersion2Attributes } from '../../../common/util/mfe'
|
|
17
17
|
|
|
18
|
+
const LOGGING_EVENT = 'Logging/Event/'
|
|
19
|
+
|
|
18
20
|
export class Aggregate extends AggregateBase {
|
|
19
21
|
static featureName = FEATURE_NAME
|
|
20
22
|
constructor (agentRef) {
|
|
21
23
|
super(agentRef, FEATURE_NAME)
|
|
22
|
-
|
|
24
|
+
const updateLocalLoggingMode = (auto, api) => {
|
|
25
|
+
this.loggingMode = { auto, api }
|
|
26
|
+
// In agent v1.290.0 & under, the logApiMode prop did not yet exist, so need to account for old session state being in-use.
|
|
27
|
+
if (api === undefined) this.loggingMode.api = auto
|
|
28
|
+
}
|
|
23
29
|
|
|
24
30
|
/** set up agg-level behaviors specific to this feature */
|
|
25
31
|
this.harvestOpts.raw = true
|
|
@@ -29,25 +35,27 @@ export class Aggregate extends AggregateBase {
|
|
|
29
35
|
this.ee.on(SESSION_EVENTS.RESET, () => {
|
|
30
36
|
this.abort(ABORT_REASONS.RESET)
|
|
31
37
|
})
|
|
32
|
-
|
|
33
38
|
this.ee.on(SESSION_EVENTS.UPDATE, (type, data) => {
|
|
34
39
|
if (this.blocked || type !== SESSION_EVENT_TYPES.CROSS_TAB) return
|
|
35
|
-
|
|
36
|
-
|
|
40
|
+
// In agent v1.290.0 & under, the logApiMode prop did not yet exist, so need to account for old session state being in-use with just loggingMode off == feature off.
|
|
41
|
+
if (data.loggingMode === LOGGING_MODE.OFF && (!data.logApiMode || data.logApiMode === LOGGING_MODE.OFF)) this.abort(ABORT_REASONS.CROSS_TAB)
|
|
42
|
+
else updateLocalLoggingMode(data.loggingMode, data.logApiMode)
|
|
37
43
|
})
|
|
38
44
|
|
|
39
|
-
this.waitForFlags(['log']).then(([
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
this.waitForFlags(['log', 'logapi']).then(([auto, api]) => {
|
|
46
|
+
if (this.blocked) return // means abort already happened before this, likely from session reset or update; abort would've set mode off + deregistered drain
|
|
47
|
+
|
|
48
|
+
this.loggingMode ??= { auto, api } // likewise, don't want to overwrite the mode if it was set already
|
|
49
|
+
const session = this.agentRef.runtime.session
|
|
50
|
+
if (canEnableSessionTracking(agentRef.init) && session) {
|
|
51
|
+
if (session.isNew) this.#syncWithSessionManager()
|
|
52
|
+
else updateLocalLoggingMode(session.state.loggingMode, session.state.logApiMode)
|
|
53
|
+
}
|
|
54
|
+
if (this.loggingMode.auto === LOGGING_MODE.OFF && this.loggingMode.api === LOGGING_MODE.OFF) {
|
|
42
55
|
this.blocked = true
|
|
43
56
|
this.deregisterDrain()
|
|
44
57
|
return
|
|
45
58
|
}
|
|
46
|
-
if (session.isNew || !this.isSessionTrackingEnabled) {
|
|
47
|
-
this.updateLoggingMode(loggingMode)
|
|
48
|
-
} else {
|
|
49
|
-
this.loggingMode = session.state.loggingMode
|
|
50
|
-
}
|
|
51
59
|
|
|
52
60
|
/** emitted by instrument class (wrapped loggers) or the api methods directly */
|
|
53
61
|
registerHandler(LOGGING_EVENT_EMITTER_CHANNEL, this.handleLog.bind(this), this.featureName, this.ee)
|
|
@@ -57,15 +65,11 @@ export class Aggregate extends AggregateBase {
|
|
|
57
65
|
})
|
|
58
66
|
}
|
|
59
67
|
|
|
60
|
-
|
|
61
|
-
this.
|
|
62
|
-
this.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
handleLog (timestamp, message, attributes = {}, level = LOG_LEVELS.INFO, target) {
|
|
68
|
-
if (this.blocked || !this.loggingMode) return
|
|
68
|
+
handleLog (timestamp, message, attributes = {}, level = LOG_LEVELS.INFO, autoCaptured, target) {
|
|
69
|
+
if (this.blocked) return
|
|
70
|
+
// Check respective logging mode depending on whether this log is from auto wrapped instrumentation or manual API that it's not turned off.
|
|
71
|
+
const modeForThisLog = autoCaptured ? this.loggingMode.auto : this.loggingMode.api
|
|
72
|
+
if (!modeForThisLog) return
|
|
69
73
|
|
|
70
74
|
if (!attributes || typeof attributes !== 'object') attributes = {}
|
|
71
75
|
|
|
@@ -77,8 +81,8 @@ export class Aggregate extends AggregateBase {
|
|
|
77
81
|
|
|
78
82
|
if (typeof level === 'string') level = level.toUpperCase()
|
|
79
83
|
if (!isValidLogLevel(level)) return warn(30, level)
|
|
80
|
-
if (
|
|
81
|
-
this.reportSupportabilityMetric('
|
|
84
|
+
if (modeForThisLog < (LOGGING_MODE[level] || Infinity)) {
|
|
85
|
+
this.reportSupportabilityMetric(LOGGING_EVENT + 'Dropped/Sampling')
|
|
82
86
|
return
|
|
83
87
|
}
|
|
84
88
|
|
|
@@ -95,7 +99,7 @@ export class Aggregate extends AggregateBase {
|
|
|
95
99
|
}
|
|
96
100
|
} catch (err) {
|
|
97
101
|
warn(16, message)
|
|
98
|
-
this.reportSupportabilityMetric('
|
|
102
|
+
this.reportSupportabilityMetric(LOGGING_EVENT + 'Dropped/Casting')
|
|
99
103
|
return
|
|
100
104
|
}
|
|
101
105
|
if (typeof message !== 'string' || !message) return warn(32)
|
|
@@ -107,7 +111,7 @@ export class Aggregate extends AggregateBase {
|
|
|
107
111
|
level
|
|
108
112
|
)
|
|
109
113
|
|
|
110
|
-
this.events.add(log)
|
|
114
|
+
if (this.events.add(log)) this.reportSupportabilityMetric(LOGGING_EVENT + (autoCaptured ? 'Auto' : 'API') + '/Added')
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
serializer (eventBuffer) {
|
|
@@ -155,13 +159,18 @@ export class Aggregate extends AggregateBase {
|
|
|
155
159
|
this.events.clear()
|
|
156
160
|
this.events.clearSave()
|
|
157
161
|
}
|
|
158
|
-
this.
|
|
162
|
+
this.loggingMode = {
|
|
163
|
+
auto: LOGGING_MODE.OFF,
|
|
164
|
+
api: LOGGING_MODE.OFF
|
|
165
|
+
}
|
|
166
|
+
this.#syncWithSessionManager()
|
|
159
167
|
this.deregisterDrain()
|
|
160
168
|
}
|
|
161
169
|
|
|
162
|
-
syncWithSessionManager (
|
|
163
|
-
|
|
164
|
-
this.
|
|
165
|
-
|
|
170
|
+
#syncWithSessionManager () {
|
|
171
|
+
this.agentRef.runtime.session?.write({
|
|
172
|
+
loggingMode: this.loggingMode.auto,
|
|
173
|
+
logApiMode: this.loggingMode.api
|
|
174
|
+
})
|
|
166
175
|
}
|
|
167
176
|
}
|
|
@@ -32,8 +32,8 @@ export class Instrument extends InstrumentBase {
|
|
|
32
32
|
|
|
33
33
|
/** emitted by wrap-logger function */
|
|
34
34
|
this.ee.on('wrap-logger-end', function handleLog ([message]) {
|
|
35
|
-
const { level, customAttributes } = this
|
|
36
|
-
bufferLog(instanceEE, message, customAttributes, level)
|
|
35
|
+
const { level, customAttributes, autoCaptured } = this
|
|
36
|
+
bufferLog(instanceEE, message, customAttributes, level, autoCaptured)
|
|
37
37
|
})
|
|
38
38
|
this.importAggregator(agentRef, () => import(/* webpackChunkName: "logging-aggregate" */ '../aggregate'))
|
|
39
39
|
}
|
|
@@ -13,11 +13,12 @@ import { LOGGING_EVENT_EMITTER_CHANNEL, LOG_LEVELS } from '../constants'
|
|
|
13
13
|
* @param {string} message - the log message string
|
|
14
14
|
* @param {{[key: string]: *}} customAttributes - The log's custom attributes if any
|
|
15
15
|
* @param {enum} level - the log level enum
|
|
16
|
+
* @param {boolean} [autoCaptured=true] - True if log was captured from auto wrapping. False if it was captured from the API manual usage.
|
|
16
17
|
* @param {object=} target - the optional target provided by an api call
|
|
17
18
|
*/
|
|
18
|
-
export function bufferLog (ee, message, customAttributes = {}, level = LOG_LEVELS.INFO, target, timestamp = now()) {
|
|
19
|
+
export function bufferLog (ee, message, customAttributes = {}, level = LOG_LEVELS.INFO, autoCaptured = true, target, timestamp = now()) {
|
|
19
20
|
handle(SUPPORTABILITY_METRIC_CHANNEL, [`API/logging/${level.toLowerCase()}/called`], undefined, FEATURE_NAMES.metrics, ee)
|
|
20
|
-
handle(LOGGING_EVENT_EMITTER_CHANNEL, [timestamp, message, customAttributes, level, target], undefined, FEATURE_NAMES.logging, ee)
|
|
21
|
+
handle(LOGGING_EVENT_EMITTER_CHANNEL, [timestamp, message, customAttributes, level, autoCaptured, target], undefined, FEATURE_NAMES.logging, ee)
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
/**
|
package/src/loaders/api/log.js
CHANGED
|
@@ -14,5 +14,5 @@ export function setupLogAPI (agent) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export function log (message, { customAttributes = {}, level = LOG_LEVELS.INFO } = {}, agentRef, target, timestamp = now()) {
|
|
17
|
-
bufferLog(agentRef.ee, message, customAttributes, level, target, timestamp)
|
|
17
|
+
bufferLog(agentRef.ee, message, customAttributes, level, false, target, timestamp)
|
|
18
18
|
}
|
|
@@ -9,6 +9,6 @@ import { setupAPI } from './sharedHandlers'
|
|
|
9
9
|
|
|
10
10
|
export function setupWrapLoggerAPI (agent) {
|
|
11
11
|
setupAPI(WRAP_LOGGER, (parent, functionName, { customAttributes = {}, level = LOG_LEVELS.INFO } = {}) => {
|
|
12
|
-
wrapLogger(agent.ee, parent, functionName, { customAttributes, level })
|
|
12
|
+
wrapLogger(agent.ee, parent, functionName, { customAttributes, level }, false)
|
|
13
13
|
}, agent)
|
|
14
14
|
}
|