Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/silly-papayas-buy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@segment/analytics-signals': minor
---

Update logging
2 changes: 1 addition & 1 deletion packages/signals/signals-example/src/lib/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const isStage = process.env.STAGE === 'true'

const signalsPlugin = new SignalsPlugin({
...(isStage ? { apiHost: 'signals.segment.build/v1' } : {}),
enableDebugLogging: true,
// enableDebugLogging: true,
// processSignal: processSignalExample,
})

Expand Down
9 changes: 8 additions & 1 deletion packages/signals/signals/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ You can *turn off debugging* by doing:
https://my-website.com?segment_signals_debug=false
```

* This also logs all signals to the js console.

#### Alternative method of enabling debug mode
In your JS console:
```js
SegmentSignalsPlugin.debug()
```

### Advanced

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

21 changes: 20 additions & 1 deletion packages/signals/signals/src/core/debug-mode/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,26 @@
export const parseDebugModeQueryString = (): boolean | undefined => {
const queryParams = new URLSearchParams(window.location.search)

const val = queryParams.get('segment_signals_debug')
const val =
queryParams.get('segment_signals_debug') ||
queryParams.get('seg_signals_debug')
if (val === 'true' || val === 'false') {
return val === 'true'
}
return undefined
}

/**
* This turns on advanced logging for signals!
*/
export const parseSignalsLoggingAdvancedQueryString = ():
| boolean
| undefined => {
const queryParams = new URLSearchParams(window.location.search)

const val =
queryParams.get('segment_signals_logging_advanced') ||
queryParams.get('seg_signals_logging_advanced')
if (val === 'true' || val === 'false') {
return val === 'true'
}
Expand Down
29 changes: 24 additions & 5 deletions packages/signals/signals/src/core/emitter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,40 @@ export interface EmitSignal {
emit: (signal: Signal) => void
}

interface SignalEmitterSettings {
shouldLogSignals: () => boolean
}

export class SignalEmitter implements EmitSignal {
private emitter = new Emitter<{ add: [Signal] }>()

private listeners = new Set<(signal: Signal) => void>()
private settings?: SignalEmitterSettings
constructor(settings?: SignalEmitterSettings) {
this.settings = settings
}
emit(signal: Signal) {
logger.debug('new signal emitted', signal)
if (this.settings?.shouldLogSignals()) {
logger.log('New signal:', signal.type, signal.data)
}
this.emitter.emit('add', signal)
}

subscribe(broadcaster: (signal: Signal) => void) {
logger.debug('subscribed')
this.emitter.on('add', broadcaster)
subscribe(listener: (signal: Signal) => void) {
// Prevent duplicate subscriptions
if (!this.listeners.has(listener)) {
logger.debug('subscribed')
this.listeners.add(listener)
}
this.emitter.on('add', listener)
}

unsubscribe(listener: (signal: Signal) => void) {
this.listeners.delete(listener)
logger.debug('unsubscribed')
this.emitter.off('add', listener)
}

once(listener: (signal: Signal) => void) {
this.emitter.once('add', listener)
}
}
74 changes: 28 additions & 46 deletions packages/signals/signals/src/core/signals/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { SignalsIngestSettingsConfig } from '../client'
import { SandboxSettingsConfig } from '../processor/sandbox'
import { NetworkSettingsConfig } from '../signal-generators/network-gen'
import { SignalsPluginSettingsConfig } from '../../types'
import { DebugStorage } from '../../lib/storage/debug-storage'

export type SignalsSettingsConfig = Pick<
SignalsPluginSettingsConfig,
Expand Down Expand Up @@ -33,9 +34,9 @@ export class SignalGlobalSettings {
signalBuffer: SignalBufferSettingsConfig
ingestClient: SignalsIngestSettingsConfig
network: NetworkSettingsConfig
signalsDebug: SignalsDebugSettings

private sampleSuccess = false
private signalsDebug = new SignalsDebugSettings()

constructor(settings: SignalsSettingsConfig) {
if (settings.maxBufferSize && settings.signalStorage) {
Expand Down Expand Up @@ -110,68 +111,49 @@ export class SignalGlobalSettings {
}
}

class SignalsDebugSettings {
export class SignalsDebugSettings {
private static redactionKey = 'segment_signals_debug_redaction_disabled'
private static ingestionKey = 'segment_signals_debug_ingestion_enabled'
private static logSignals = 'segment_signals_log_signals_enabled'
storage: DebugStorage

constructor(disableRedaction?: boolean, enableIngestion?: boolean) {
this.storage = new DebugStorage('sessionStorage')
if (typeof disableRedaction === 'boolean') {
this.setDebugKey(SignalsDebugSettings.redactionKey, disableRedaction)
this.storage.setDebugKey(
SignalsDebugSettings.redactionKey,
disableRedaction
)
}
if (typeof enableIngestion === 'boolean') {
this.setDebugKey(SignalsDebugSettings.ingestionKey, enableIngestion)
this.storage.setDebugKey(
SignalsDebugSettings.ingestionKey,
enableIngestion
)
}

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

setDebugKey(key: string, enable: boolean) {
try {
if (enable) {
window.sessionStorage.setItem(key, 'true')
} else {
logger.debug(`Removing debug key ${key} from storage`)
window.sessionStorage.removeItem(key)
}
} catch (e) {
logger.debug('Storage error', e)
}
setAllDebugging = (boolean: boolean) => {
this.storage.setDebugKey(SignalsDebugSettings.redactionKey, boolean)
this.storage.setDebugKey(SignalsDebugSettings.ingestionKey, boolean)
this.storage.setDebugKey(SignalsDebugSettings.logSignals, boolean)
}

getDisableSignalsRedaction() {
try {
const isEnabled = Boolean(
window.sessionStorage.getItem(SignalsDebugSettings.redactionKey)
)
if (isEnabled) {
logger.debug(`${SignalsDebugSettings.redactionKey}=true (app. storage)`)
return true
}
} catch (e) {
logger.debug('Storage error', e)
}
return false
getDisableSignalsRedaction = (): boolean => {
return this.storage.getDebugKey(SignalsDebugSettings.redactionKey)
}

getEnableSignalsIngestion() {
try {
const isEnabled = Boolean(
window.sessionStorage.getItem(SignalsDebugSettings.ingestionKey)
)
if (isEnabled) {
logger.debug(`${SignalsDebugSettings.ingestionKey}=true (app. storage)`)
return true
}
} catch (e) {
logger.debug('Storage error', e)
}
return false
getEnableSignalsIngestion = (): boolean => {
return this.storage.getDebugKey(SignalsDebugSettings.ingestionKey)
}

getEnableLogSignals = (): boolean => {
return this.storage.getDebugKey(SignalsDebugSettings.logSignals)
}
}
14 changes: 12 additions & 2 deletions packages/signals/signals/src/core/signals/signals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ export class Signals implements ISignals {
private globalSettings: SignalGlobalSettings
constructor(settingsConfig: SignalsSettingsConfig = {}) {
this.globalSettings = new SignalGlobalSettings(settingsConfig)
this.signalEmitter = new SignalEmitter()
this.signalEmitter = new SignalEmitter({
shouldLogSignals: () =>
this.globalSettings.signalsDebug.getEnableLogSignals(),
})
this.signalsClient = new SignalsIngestClient(
this.globalSettings.ingestClient
)
Expand Down Expand Up @@ -130,7 +133,14 @@ export class Signals implements ISignals {
}

/**
* Emit custom signals.
* Disable redaction, ingestion of signals, and other debug logging.
*/
debug(boolean = true): void {
this.globalSettings.signalsDebug.setAllDebugging(boolean)
}

/**
* Register custom signal generators to emit signals.
*/
async registerGenerator(
generators: (SignalGeneratorClass | SignalGenerator)[]
Expand Down
30 changes: 23 additions & 7 deletions packages/signals/signals/src/lib/logger/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
import { parseSignalsLoggingAdvancedQueryString } from '../../core/debug-mode'
import { DebugStorage } from '../storage/debug-storage'

class Logger {
globalKey = 'SEGMENT_SIGNALS_DEBUG'
get debugLoggingEnabled() {
return (window as any)[this.globalKey] === true
private static advancedLogging = 'segment_signals_logging_advanced'

storage = new DebugStorage('sessionStorage')
constructor() {
const val = parseSignalsLoggingAdvancedQueryString()
if (typeof val === 'boolean') {
this.storage.setDebugKey(Logger.advancedLogging, val)
}
}

private debugLoggingEnabled = (): boolean => {
return this.storage.getDebugKey(Logger.advancedLogging)
}

enableDebugLogging = (bool = true) => {
this.storage.setDebugKey(Logger.advancedLogging, bool)
}

enableDebugLogging() {
;(window as any)[this.globalKey] = true
log = (...args: any[]): void => {
console.log('[signals log]', ...args)
}

debug(...args: any[]): void {
if (this.debugLoggingEnabled) {
debug = (...args: any[]): void => {
if (this.debugLoggingEnabled()) {
console.log('[signals debug]', ...args)
}
}
Expand Down
29 changes: 29 additions & 0 deletions packages/signals/signals/src/lib/storage/debug-storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export class DebugStorage {
private storageType: 'localStorage' | 'sessionStorage'
constructor(type: 'localStorage' | 'sessionStorage') {
this.storageType = type
}
public setDebugKey = (key: string, enable: boolean): void => {
try {
if (enable) {
window[this.storageType].setItem(key, 'true')
} else {
window.sessionStorage.removeItem(key)
}
} catch (e) {
console.warn('Storage error', e)
}
}

public getDebugKey = (key: string): boolean => {
try {
const isEnabled = Boolean(window[this.storageType].getItem(key))
if (isEnabled) {
return true
}
} catch (e) {
console.warn('Storage error', e)
}
return false
}
}
17 changes: 15 additions & 2 deletions packages/signals/signals/src/plugin/signals-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,19 @@ export class SignalsPlugin implements Plugin, SignalsAugmentedFunctionality {
readonly name = 'SignalsPlugin'
readonly version = version
public signals: Signals

constructor(settings: SignalsPluginSettingsConfig = {}) {
assertBrowserEnv()

// assign to window for debugging purposes
Object.assign(window, { SegmentSignalsPlugin: this })

if (settings.enableDebugLogging) {
logger.enableDebugLogging()
}
logger.debug('SignalsPlugin initializing', { settings })

logger.debug(`SignalsPlugin v${version} initializing`, {
settings,
})

this.signals = new Signals({
disableSignalsRedaction: settings.disableSignalsRedaction,
Expand Down Expand Up @@ -79,4 +85,11 @@ export class SignalsPlugin implements Plugin, SignalsAugmentedFunctionality {
this.signals.signalEmitter.emit(signal)
return this
}

/**
* Enable redaction and disable ingestion of signals. Also, logs signals to the console.
*/
debug(boolean = true): void {
this.signals.debug(boolean)
}
}
2 changes: 1 addition & 1 deletion packages/signals/signals/src/types/process-signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export interface AnalyticsRuntimePublicApi {

export type ProcessSignalScope = {
analytics: AnalyticsRuntimePublicApi
signals: SignalsRuntime
signals: SignalsRuntime<Signal>
} & typeof WebRuntimeConstants

export interface ProcessSignal {
Expand Down
Loading