Skip to content

Commit ccc97f1

Browse files
authored
Log signals if debug mode is on (#1184)
1 parent 2fc4c9c commit ccc97f1

File tree

11 files changed

+166
-66
lines changed

11 files changed

+166
-66
lines changed

.changeset/silly-papayas-buy.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@segment/analytics-signals': minor
3+
---
4+
5+
Update logging

packages/signals/signals-example/src/lib/analytics.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const isStage = process.env.STAGE === 'true'
3333

3434
const signalsPlugin = new SignalsPlugin({
3535
...(isStage ? { apiHost: 'signals.segment.build/v1' } : {}),
36-
enableDebugLogging: true,
36+
// enableDebugLogging: true,
3737
// processSignal: processSignalExample,
3838
})
3939

packages/signals/signals/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ You can *turn off debugging* by doing:
7777
https://my-website.com?segment_signals_debug=false
7878
```
7979

80+
* This also logs all signals to the js console.
81+
82+
#### Alternative method of enabling debug mode
83+
In your JS console:
84+
```js
85+
SegmentSignalsPlugin.debug()
86+
```
87+
8088
### Advanced
8189

8290
#### Listening to signals
@@ -108,4 +116,3 @@ Network signals emit when an HTTP Request is made, or an HTTP Response is receiv
108116
- Initiated using the `fetch` API
109117
- First party domain (e.g if on `foo.com`, then `foo.com/api/products`, but not `bar.com/api/products`)
110118
- Contains the content-type: `application/json`
111-

packages/signals/signals/src/core/debug-mode/index.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,26 @@
55
export const parseDebugModeQueryString = (): boolean | undefined => {
66
const queryParams = new URLSearchParams(window.location.search)
77

8-
const val = queryParams.get('segment_signals_debug')
8+
const val =
9+
queryParams.get('segment_signals_debug') ||
10+
queryParams.get('seg_signals_debug')
11+
if (val === 'true' || val === 'false') {
12+
return val === 'true'
13+
}
14+
return undefined
15+
}
16+
17+
/**
18+
* This turns on advanced logging for signals!
19+
*/
20+
export const parseSignalsLoggingAdvancedQueryString = ():
21+
| boolean
22+
| undefined => {
23+
const queryParams = new URLSearchParams(window.location.search)
24+
25+
const val =
26+
queryParams.get('segment_signals_logging_advanced') ||
27+
queryParams.get('seg_signals_logging_advanced')
928
if (val === 'true' || val === 'false') {
1029
return val === 'true'
1130
}

packages/signals/signals/src/core/emitter/index.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,40 @@ export interface EmitSignal {
66
emit: (signal: Signal) => void
77
}
88

9+
interface SignalEmitterSettings {
10+
shouldLogSignals: () => boolean
11+
}
12+
913
export class SignalEmitter implements EmitSignal {
1014
private emitter = new Emitter<{ add: [Signal] }>()
11-
15+
private listeners = new Set<(signal: Signal) => void>()
16+
private settings?: SignalEmitterSettings
17+
constructor(settings?: SignalEmitterSettings) {
18+
this.settings = settings
19+
}
1220
emit(signal: Signal) {
13-
logger.debug('new signal emitted', signal)
21+
if (this.settings?.shouldLogSignals()) {
22+
logger.log('New signal:', signal.type, signal.data)
23+
}
1424
this.emitter.emit('add', signal)
1525
}
1626

17-
subscribe(broadcaster: (signal: Signal) => void) {
18-
logger.debug('subscribed')
19-
this.emitter.on('add', broadcaster)
27+
subscribe(listener: (signal: Signal) => void) {
28+
// Prevent duplicate subscriptions
29+
if (!this.listeners.has(listener)) {
30+
logger.debug('subscribed')
31+
this.listeners.add(listener)
32+
}
33+
this.emitter.on('add', listener)
2034
}
2135

2236
unsubscribe(listener: (signal: Signal) => void) {
37+
this.listeners.delete(listener)
2338
logger.debug('unsubscribed')
2439
this.emitter.off('add', listener)
2540
}
41+
42+
once(listener: (signal: Signal) => void) {
43+
this.emitter.once('add', listener)
44+
}
2645
}

packages/signals/signals/src/core/signals/settings.ts

Lines changed: 28 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { SignalsIngestSettingsConfig } from '../client'
55
import { SandboxSettingsConfig } from '../processor/sandbox'
66
import { NetworkSettingsConfig } from '../signal-generators/network-gen'
77
import { SignalsPluginSettingsConfig } from '../../types'
8+
import { DebugStorage } from '../../lib/storage/debug-storage'
89

910
export type SignalsSettingsConfig = Pick<
1011
SignalsPluginSettingsConfig,
@@ -33,9 +34,9 @@ export class SignalGlobalSettings {
3334
signalBuffer: SignalBufferSettingsConfig
3435
ingestClient: SignalsIngestSettingsConfig
3536
network: NetworkSettingsConfig
37+
signalsDebug: SignalsDebugSettings
3638

3739
private sampleSuccess = false
38-
private signalsDebug = new SignalsDebugSettings()
3940

4041
constructor(settings: SignalsSettingsConfig) {
4142
if (settings.maxBufferSize && settings.signalStorage) {
@@ -110,68 +111,49 @@ export class SignalGlobalSettings {
110111
}
111112
}
112113

113-
class SignalsDebugSettings {
114+
export class SignalsDebugSettings {
114115
private static redactionKey = 'segment_signals_debug_redaction_disabled'
115116
private static ingestionKey = 'segment_signals_debug_ingestion_enabled'
117+
private static logSignals = 'segment_signals_log_signals_enabled'
118+
storage: DebugStorage
119+
116120
constructor(disableRedaction?: boolean, enableIngestion?: boolean) {
121+
this.storage = new DebugStorage('sessionStorage')
117122
if (typeof disableRedaction === 'boolean') {
118-
this.setDebugKey(SignalsDebugSettings.redactionKey, disableRedaction)
123+
this.storage.setDebugKey(
124+
SignalsDebugSettings.redactionKey,
125+
disableRedaction
126+
)
119127
}
120128
if (typeof enableIngestion === 'boolean') {
121-
this.setDebugKey(SignalsDebugSettings.ingestionKey, enableIngestion)
129+
this.storage.setDebugKey(
130+
SignalsDebugSettings.ingestionKey,
131+
enableIngestion
132+
)
122133
}
123134

124-
// setting ?segment_signals_debug=true will disable redaction, enable ingestion, and set keys in local storage
125-
// this setting will persist across page loads (even if there is no query string)
126-
// in order to clear the setting, user must set ?segment_signals_debug=false
127135
const debugModeInQs = parseDebugModeQueryString()
128136
logger.debug('debugMode is set to true via query string')
129137
if (typeof debugModeInQs === 'boolean') {
130-
this.setDebugKey(SignalsDebugSettings.redactionKey, debugModeInQs)
131-
this.setDebugKey(SignalsDebugSettings.ingestionKey, debugModeInQs)
138+
this.setAllDebugging(debugModeInQs)
132139
}
133140
}
134141

135-
setDebugKey(key: string, enable: boolean) {
136-
try {
137-
if (enable) {
138-
window.sessionStorage.setItem(key, 'true')
139-
} else {
140-
logger.debug(`Removing debug key ${key} from storage`)
141-
window.sessionStorage.removeItem(key)
142-
}
143-
} catch (e) {
144-
logger.debug('Storage error', e)
145-
}
142+
setAllDebugging = (boolean: boolean) => {
143+
this.storage.setDebugKey(SignalsDebugSettings.redactionKey, boolean)
144+
this.storage.setDebugKey(SignalsDebugSettings.ingestionKey, boolean)
145+
this.storage.setDebugKey(SignalsDebugSettings.logSignals, boolean)
146146
}
147147

148-
getDisableSignalsRedaction() {
149-
try {
150-
const isEnabled = Boolean(
151-
window.sessionStorage.getItem(SignalsDebugSettings.redactionKey)
152-
)
153-
if (isEnabled) {
154-
logger.debug(`${SignalsDebugSettings.redactionKey}=true (app. storage)`)
155-
return true
156-
}
157-
} catch (e) {
158-
logger.debug('Storage error', e)
159-
}
160-
return false
148+
getDisableSignalsRedaction = (): boolean => {
149+
return this.storage.getDebugKey(SignalsDebugSettings.redactionKey)
161150
}
162151

163-
getEnableSignalsIngestion() {
164-
try {
165-
const isEnabled = Boolean(
166-
window.sessionStorage.getItem(SignalsDebugSettings.ingestionKey)
167-
)
168-
if (isEnabled) {
169-
logger.debug(`${SignalsDebugSettings.ingestionKey}=true (app. storage)`)
170-
return true
171-
}
172-
} catch (e) {
173-
logger.debug('Storage error', e)
174-
}
175-
return false
152+
getEnableSignalsIngestion = (): boolean => {
153+
return this.storage.getDebugKey(SignalsDebugSettings.ingestionKey)
154+
}
155+
156+
getEnableLogSignals = (): boolean => {
157+
return this.storage.getDebugKey(SignalsDebugSettings.logSignals)
176158
}
177159
}

packages/signals/signals/src/core/signals/signals.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ export class Signals implements ISignals {
3838
private globalSettings: SignalGlobalSettings
3939
constructor(settingsConfig: SignalsSettingsConfig = {}) {
4040
this.globalSettings = new SignalGlobalSettings(settingsConfig)
41-
this.signalEmitter = new SignalEmitter()
41+
this.signalEmitter = new SignalEmitter({
42+
shouldLogSignals: () =>
43+
this.globalSettings.signalsDebug.getEnableLogSignals(),
44+
})
4245
this.signalsClient = new SignalsIngestClient(
4346
this.globalSettings.ingestClient
4447
)
@@ -130,7 +133,14 @@ export class Signals implements ISignals {
130133
}
131134

132135
/**
133-
* Emit custom signals.
136+
* Disable redaction, ingestion of signals, and other debug logging.
137+
*/
138+
debug(boolean = true): void {
139+
this.globalSettings.signalsDebug.setAllDebugging(boolean)
140+
}
141+
142+
/**
143+
* Register custom signal generators to emit signals.
134144
*/
135145
async registerGenerator(
136146
generators: (SignalGeneratorClass | SignalGenerator)[]

packages/signals/signals/src/lib/logger/index.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
1+
import { parseSignalsLoggingAdvancedQueryString } from '../../core/debug-mode'
2+
import { DebugStorage } from '../storage/debug-storage'
3+
14
class Logger {
2-
globalKey = 'SEGMENT_SIGNALS_DEBUG'
3-
get debugLoggingEnabled() {
4-
return (window as any)[this.globalKey] === true
5+
private static advancedLogging = 'segment_signals_logging_advanced'
6+
7+
storage = new DebugStorage('sessionStorage')
8+
constructor() {
9+
const val = parseSignalsLoggingAdvancedQueryString()
10+
if (typeof val === 'boolean') {
11+
this.storage.setDebugKey(Logger.advancedLogging, val)
12+
}
13+
}
14+
15+
private debugLoggingEnabled = (): boolean => {
16+
return this.storage.getDebugKey(Logger.advancedLogging)
17+
}
18+
19+
enableDebugLogging = (bool = true) => {
20+
this.storage.setDebugKey(Logger.advancedLogging, bool)
521
}
622

7-
enableDebugLogging() {
8-
;(window as any)[this.globalKey] = true
23+
log = (...args: any[]): void => {
24+
console.log('[signals log]', ...args)
925
}
1026

11-
debug(...args: any[]): void {
12-
if (this.debugLoggingEnabled) {
27+
debug = (...args: any[]): void => {
28+
if (this.debugLoggingEnabled()) {
1329
console.log('[signals debug]', ...args)
1430
}
1531
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
export class DebugStorage {
2+
private storageType: 'localStorage' | 'sessionStorage'
3+
constructor(type: 'localStorage' | 'sessionStorage') {
4+
this.storageType = type
5+
}
6+
public setDebugKey = (key: string, enable: boolean): void => {
7+
try {
8+
if (enable) {
9+
window[this.storageType].setItem(key, 'true')
10+
} else {
11+
window.sessionStorage.removeItem(key)
12+
}
13+
} catch (e) {
14+
console.warn('Storage error', e)
15+
}
16+
}
17+
18+
public getDebugKey = (key: string): boolean => {
19+
try {
20+
const isEnabled = Boolean(window[this.storageType].getItem(key))
21+
if (isEnabled) {
22+
return true
23+
}
24+
} catch (e) {
25+
console.warn('Storage error', e)
26+
}
27+
return false
28+
}
29+
}

packages/signals/signals/src/plugin/signals-plugin.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,19 @@ export class SignalsPlugin implements Plugin, SignalsAugmentedFunctionality {
2626
readonly name = 'SignalsPlugin'
2727
readonly version = version
2828
public signals: Signals
29-
3029
constructor(settings: SignalsPluginSettingsConfig = {}) {
3130
assertBrowserEnv()
31+
32+
// assign to window for debugging purposes
33+
Object.assign(window, { SegmentSignalsPlugin: this })
34+
3235
if (settings.enableDebugLogging) {
3336
logger.enableDebugLogging()
3437
}
35-
logger.debug('SignalsPlugin initializing', { settings })
38+
39+
logger.debug(`SignalsPlugin v${version} initializing`, {
40+
settings,
41+
})
3642

3743
this.signals = new Signals({
3844
disableSignalsRedaction: settings.disableSignalsRedaction,
@@ -79,4 +85,11 @@ export class SignalsPlugin implements Plugin, SignalsAugmentedFunctionality {
7985
this.signals.signalEmitter.emit(signal)
8086
return this
8187
}
88+
89+
/**
90+
* Enable redaction and disable ingestion of signals. Also, logs signals to the console.
91+
*/
92+
debug(boolean = true): void {
93+
this.signals.debug(boolean)
94+
}
8295
}

0 commit comments

Comments
 (0)