diff --git a/CHANGELOG.md b/CHANGELOG.md index 58e2407be..fdc71a3e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.194.5 - 2024-12-06 + +- feat: Added better sub logging utils (#1581) + ## 1.194.4 - 2024-12-05 - feat: RemoteConfig loader (#1577) diff --git a/functional_tests/feature-flags.test.ts b/functional_tests/feature-flags.test.ts index d6ec89b17..d2fd05fbf 100644 --- a/functional_tests/feature-flags.test.ts +++ b/functional_tests/feature-flags.test.ts @@ -1,3 +1,5 @@ +import '../src/__tests__/helpers/mock-logger' + import { createPosthogInstance } from '../src/__tests__/helpers/posthog-instance' import { waitFor } from '@testing-library/dom' import { getRequests, resetRequests } from './mock-server' diff --git a/functional_tests/identify.test.ts b/functional_tests/identify.test.ts index b91f8d2e3..3f53aa1b4 100644 --- a/functional_tests/identify.test.ts +++ b/functional_tests/identify.test.ts @@ -1,3 +1,5 @@ +import '../src/__tests__/helpers/mock-logger' + import 'regenerator-runtime/runtime' import { waitFor } from '@testing-library/dom' import { getRequests } from './mock-server' @@ -5,7 +7,6 @@ import { createPosthogInstance } from '../src/__tests__/helpers/posthog-instance import { logger } from '../src/utils/logger' import { uuidv7 } from '../src/uuidv7' import { PostHog } from '../src/posthog-core' -jest.mock('../src/utils/logger') describe('FunctionalTests / Identify', () => { let token: string diff --git a/package.json b/package.json index 4a42b0052..14c2f2317 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "posthog-js", - "version": "1.194.4", + "version": "1.194.5", "description": "Posthog-js allows you to automatically capture usage and send events to PostHog.", "repository": "https://github.com/PostHog/posthog-js", "author": "hey@posthog.com", diff --git a/src/__tests__/consent.test.ts b/src/__tests__/consent.test.ts index b6f520ee5..7eccd199f 100644 --- a/src/__tests__/consent.test.ts +++ b/src/__tests__/consent.test.ts @@ -1,3 +1,5 @@ +import './helpers/mock-logger' + import { PostHog } from '../posthog-core' import { defaultPostHog } from './helpers/posthog-instance' import { uuidv7 } from '../uuidv7' diff --git a/src/__tests__/decide.ts b/src/__tests__/decide.ts index b770283ac..a7c8ec266 100644 --- a/src/__tests__/decide.ts +++ b/src/__tests__/decide.ts @@ -212,7 +212,10 @@ describe('Decide', () => { subject(undefined as unknown as DecideResponse) expect(posthog.featureFlags.receivedFeatureFlags).toHaveBeenCalledWith({}, true) - expect(console.error).toHaveBeenCalledWith('[PostHog.js]', 'Failed to fetch feature flags from PostHog.') + expect(console.error).toHaveBeenCalledWith( + '[PostHog.js] [Decide]', + 'Failed to fetch feature flags from PostHog.' + ) }) it('Make sure receivedFeatureFlags is not called if advanced_disable_feature_flags_on_first_load is set', () => { diff --git a/src/__tests__/extensions/web-vitals.test.ts b/src/__tests__/extensions/web-vitals.test.ts index b28aeb125..0aa4450fc 100644 --- a/src/__tests__/extensions/web-vitals.test.ts +++ b/src/__tests__/extensions/web-vitals.test.ts @@ -1,3 +1,5 @@ +import '../helpers/mock-logger' + import { createPosthogInstance } from '../helpers/posthog-instance' import { uuidv7 } from '../../uuidv7' import { PostHog } from '../../posthog-core' @@ -5,7 +7,6 @@ import { DecideResponse, PerformanceCaptureConfig, SupportedWebVitalsMetrics } f import { assignableWindow } from '../../utils/globals' import { DEFAULT_FLUSH_TO_CAPTURE_TIMEOUT_MILLISECONDS, FIFTEEN_MINUTES_IN_MILLIS } from '../../extensions/web-vitals' -jest.mock('../../utils/logger') jest.useFakeTimers() describe('web vitals', () => { diff --git a/src/__tests__/featureflags.ts b/src/__tests__/featureflags.ts index 0de1ee386..fd2b5792c 100644 --- a/src/__tests__/featureflags.ts +++ b/src/__tests__/featureflags.ts @@ -88,7 +88,7 @@ describe('featureflags', () => { expect(featureFlags.getFlags()).toEqual([]) expect(featureFlags.isFeatureEnabled('beta-feature')).toEqual(undefined) expect(window.console.warn).toHaveBeenCalledWith( - '[PostHog.js]', + '[PostHog.js] [FeatureFlags]', 'isFeatureEnabled for key "beta-feature" failed. Feature flags didn\'t load in time.' ) @@ -96,7 +96,7 @@ describe('featureflags', () => { expect(featureFlags.getFeatureFlag('beta-feature')).toEqual(undefined) expect(window.console.warn).toHaveBeenCalledWith( - '[PostHog.js]', + '[PostHog.js] [FeatureFlags]', 'getFeatureFlag for key "beta-feature" failed. Feature flags didn\'t load in time.' ) }) @@ -247,7 +247,7 @@ describe('featureflags', () => { 'alpha-feature-2': true, }) expect(window.console.warn).toHaveBeenCalledWith( - '[PostHog.js]', + '[PostHog.js] [FeatureFlags]', ' Overriding feature flags!', expect.any(Object) ) diff --git a/src/__tests__/heatmaps.test.ts b/src/__tests__/heatmaps.test.ts index 5168c8a37..a346cd476 100644 --- a/src/__tests__/heatmaps.test.ts +++ b/src/__tests__/heatmaps.test.ts @@ -1,3 +1,5 @@ +import './helpers/mock-logger' + import { createPosthogInstance } from './helpers/posthog-instance' import { uuidv7 } from '../uuidv7' import { PostHog } from '../posthog-core' @@ -7,7 +9,6 @@ import { beforeEach, expect } from '@jest/globals' import { HEATMAPS_ENABLED_SERVER_SIDE } from '../constants' import { Heatmaps } from '../heatmaps' -jest.mock('../utils/logger') jest.useFakeTimers() describe('heatmaps', () => { diff --git a/src/__tests__/helpers/mock-logger.ts b/src/__tests__/helpers/mock-logger.ts new file mode 100644 index 000000000..b230cde9e --- /dev/null +++ b/src/__tests__/helpers/mock-logger.ts @@ -0,0 +1,32 @@ +import { Logger } from '../../utils/logger' + +jest.mock('../../utils/logger', () => { + const mockLogger: Logger = { + _log: jest.fn(), + critical: jest.fn(), + uninitializedWarning: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + createLogger: () => { + return mockLogger + }, + } + return { + logger: mockLogger, + createLogger: mockLogger.createLogger, + } +}) + +import { logger } from '../../utils/logger' +import { isFunction } from '../../utils/type-utils' + +export const clearLoggerMocks = () => { + Object.values(logger).forEach((mock: any) => { + if (isFunction(mock.mockClear)) { + mock.mockClear() + } + }) +} + +export const mockLogger: jest.Mocked = logger as any diff --git a/src/__tests__/identify.test.ts b/src/__tests__/identify.test.ts index d9f37571d..6c9e6139d 100644 --- a/src/__tests__/identify.test.ts +++ b/src/__tests__/identify.test.ts @@ -1,7 +1,7 @@ +import { mockLogger } from './helpers/mock-logger' + import { createPosthogInstance } from './helpers/posthog-instance' -import { logger } from '../utils/logger' import { uuidv7 } from '../uuidv7' -jest.mock('../utils/logger') describe('identify', () => { // Note that there are other tests for identify in posthog-core.identify.js @@ -19,8 +19,8 @@ describe('identify', () => { // assert expect(posthog.persistence!.properties()['$user_id']).toEqual(distinctId) - expect(jest.mocked(logger).error).toBeCalledTimes(0) - expect(jest.mocked(logger).warn).toBeCalledTimes(0) + expect(mockLogger.error).toBeCalledTimes(0) + expect(mockLogger.warn).toBeCalledTimes(0) }) it('should convert a numeric distinct_id to a string', async () => { @@ -35,8 +35,8 @@ describe('identify', () => { // assert expect(posthog.persistence!.properties()['$user_id']).toEqual(distinctIdString) - expect(jest.mocked(logger).error).toBeCalledTimes(0) - expect(jest.mocked(logger).warn).toBeCalledTimes(1) + expect(mockLogger.error).toBeCalledTimes(0) + expect(mockLogger.warn).toBeCalledTimes(1) }) it('should send $is_identified = true with the identify event and following events', async () => { diff --git a/src/__tests__/personProcessing.test.ts b/src/__tests__/personProcessing.test.ts index 12abe13b3..058dedb42 100644 --- a/src/__tests__/personProcessing.test.ts +++ b/src/__tests__/personProcessing.test.ts @@ -1,11 +1,10 @@ +import { mockLogger } from './helpers/mock-logger' + import { createPosthogInstance } from './helpers/posthog-instance' import { uuidv7 } from '../uuidv7' -import { logger } from '../utils/logger' import { INITIAL_CAMPAIGN_PARAMS, INITIAL_REFERRER_INFO } from '../constants' import { RemoteConfig } from '../types' -jest.mock('../utils/logger') - const INITIAL_CAMPAIGN_PARAMS_NULL = { $initial_current_url: null, $initial_dclid: null, @@ -156,8 +155,8 @@ describe('person processing', () => { posthog.identify(distinctId) // assert - expect(jest.mocked(logger).error).toBeCalledTimes(1) - expect(jest.mocked(logger).error).toHaveBeenCalledWith( + expect(mockLogger.error).toBeCalledTimes(1) + expect(mockLogger.error).toHaveBeenCalledWith( 'posthog.identify was called, but process_person is set to "never". This call will be ignored.' ) expect(beforeSendMock).toBeCalledTimes(0) @@ -172,7 +171,7 @@ describe('person processing', () => { posthog.identify(distinctId) posthog.capture('custom event after identify') // assert - expect(jest.mocked(logger).error).toBeCalledTimes(0) + expect(mockLogger.error).toBeCalledTimes(0) const eventBeforeIdentify = beforeSendMock.mock.calls[0] expect(eventBeforeIdentify[0].properties.$process_person_profile).toEqual(false) const identifyCall = beforeSendMock.mock.calls[1] @@ -191,7 +190,7 @@ describe('person processing', () => { posthog.identify(distinctId) posthog.capture('custom event after identify') // assert - expect(jest.mocked(logger).error).toBeCalledTimes(0) + expect(mockLogger.error).toBeCalledTimes(0) const eventBeforeIdentify = beforeSendMock.mock.calls[0] expect(eventBeforeIdentify[0].properties.$process_person_profile).toEqual(true) const identifyCall = beforeSendMock.mock.calls[1] @@ -503,8 +502,8 @@ describe('person processing', () => { posthog.capture('custom event after group') // assert - expect(jest.mocked(logger).error).toBeCalledTimes(1) - expect(jest.mocked(logger).error).toHaveBeenCalledWith( + expect(mockLogger.error).toBeCalledTimes(1) + expect(mockLogger.error).toHaveBeenCalledWith( 'posthog.group was called, but process_person is set to "never". This call will be ignored.' ) @@ -526,8 +525,8 @@ describe('person processing', () => { // assert expect(beforeSendMock).toBeCalledTimes(0) - expect(jest.mocked(logger).error).toBeCalledTimes(1) - expect(jest.mocked(logger).error).toHaveBeenCalledWith( + expect(mockLogger.error).toBeCalledTimes(1) + expect(mockLogger.error).toHaveBeenCalledWith( 'posthog.setPersonProperties was called, but process_person is set to "never". This call will be ignored.' ) }) @@ -593,8 +592,8 @@ describe('person processing', () => { // assert expect(beforeSendMock).toBeCalledTimes(0) - expect(jest.mocked(logger).error).toBeCalledTimes(1) - expect(jest.mocked(logger).error).toHaveBeenCalledWith( + expect(mockLogger.error).toBeCalledTimes(1) + expect(mockLogger.error).toHaveBeenCalledWith( 'posthog.alias was called, but process_person is set to "never". This call will be ignored.' ) }) @@ -644,7 +643,7 @@ describe('person processing', () => { // assert expect(beforeSendMock).toBeCalledTimes(0) - expect(jest.mocked(logger).error).toBeCalledTimes(0) + expect(mockLogger.error).toBeCalledTimes(0) }) }) diff --git a/src/__tests__/posthog-core.beforeSend.test.ts b/src/__tests__/posthog-core.beforeSend.test.ts index 35d0a4641..d4f1c0322 100644 --- a/src/__tests__/posthog-core.beforeSend.test.ts +++ b/src/__tests__/posthog-core.beforeSend.test.ts @@ -1,11 +1,10 @@ +import { mockLogger } from './helpers/mock-logger' + import { uuidv7 } from '../uuidv7' import { defaultPostHog } from './helpers/posthog-instance' -import { logger } from '../utils/logger' import { CaptureResult, knownUnsafeEditableEvent, PostHogConfig } from '../types' import { PostHog } from '../posthog-core' -jest.mock('../utils/logger') - const rejectingEventFn = () => { return null } @@ -53,9 +52,7 @@ describe('posthog core - before send', () => { expect(capturedData).toBeUndefined() expect(posthog._send_request).not.toHaveBeenCalled() - expect(jest.mocked(logger).info).toHaveBeenCalledWith( - `Event '${eventName}' was rejected in beforeSend function` - ) + expect(mockLogger.info).toHaveBeenCalledWith(`Event '${eventName}' was rejected in beforeSend function`) }) it('can edit an event', () => { @@ -156,7 +153,7 @@ describe('posthog core - before send', () => { method: 'POST', url: 'https://us.i.posthog.com/e/', }) - expect(jest.mocked(logger).warn).toHaveBeenCalledWith( + expect(mockLogger.warn).toHaveBeenCalledWith( `Event '${eventName}' has no properties after beforeSend function, this is likely an error.` ) }) @@ -172,7 +169,7 @@ describe('posthog core - before send', () => { posthog.capture(randomUnsafeEditableEvent, {}, {}) - expect(jest.mocked(logger).warn).toHaveBeenCalledWith( + expect(mockLogger.warn).toHaveBeenCalledWith( `Event '${randomUnsafeEditableEvent}' was rejected in beforeSend function. This can cause unexpected behavior.` ) }) diff --git a/src/__tests__/posthog-core.ts b/src/__tests__/posthog-core.ts index 25026ef0a..0579706b4 100644 --- a/src/__tests__/posthog-core.ts +++ b/src/__tests__/posthog-core.ts @@ -1,10 +1,11 @@ +import { mockLogger } from './helpers/mock-logger' + import { Info } from '../utils/event-utils' import { document, window } from '../utils/globals' import { uuidv7 } from '../uuidv7' import * as globals from '../utils/globals' import { ENABLE_PERSON_PROCESSING, USER_STATE } from '../constants' import { createPosthogInstance, defaultPostHog } from './helpers/posthog-instance' -import { logger } from '../utils/logger' import { PostHogConfig, RemoteConfig } from '../types' import { PostHog } from '../posthog-core' import { PostHogPersistence } from '../posthog-persistence' @@ -119,16 +120,14 @@ describe('posthog core', () => { const posthog = posthogWith(defaultConfig, defaultOverrides) posthog._addCaptureHook(hook) - jest.spyOn(logger, 'error').mockImplementation() expect(() => posthog.capture(undefined)).not.toThrow() expect(hook).not.toHaveBeenCalled() - expect(logger.error).toHaveBeenCalledWith('No event name provided to posthog.capture') + expect(mockLogger.error).toHaveBeenCalledWith('No event name provided to posthog.capture') }) it('errors with object event name', () => { const hook = jest.fn() - jest.spyOn(logger, 'error').mockImplementation() const posthog = posthogWith(defaultConfig, defaultOverrides) posthog._addCaptureHook(hook) @@ -136,7 +135,7 @@ describe('posthog core', () => { // @ts-expect-error - testing invalid input expect(() => posthog.capture({ event: 'object as name' })).not.toThrow() expect(hook).not.toHaveBeenCalled() - expect(logger.error).toHaveBeenCalledWith('No event name provided to posthog.capture') + expect(mockLogger.error).toHaveBeenCalledWith('No event name provided to posthog.capture') }) it('respects opt_out_useragent_filter (default: false)', () => { @@ -746,8 +745,6 @@ describe('posthog core', () => { }) it('does nothing when empty', () => { - jest.spyOn(logger, 'warn').mockImplementation() - const posthog = posthogWith({ bootstrap: {}, persistence: 'memory', @@ -756,7 +753,7 @@ describe('posthog core', () => { expect(posthog.get_distinct_id()).not.toBe('abcd') expect(posthog.get_distinct_id()).not.toEqual(undefined) expect(posthog.getFeatureFlag('multivariant')).toBe(undefined) - expect(logger.warn).toHaveBeenCalledWith( + expect(mockLogger.warn).toHaveBeenCalledWith( expect.stringContaining('getFeatureFlag for key "multivariant" failed') ) expect(posthog.getFeatureFlag('disabled')).toBe(undefined) @@ -902,11 +899,9 @@ describe('posthog core', () => { describe('skipped init()', () => { it('capture() does not throw', () => { - jest.spyOn(logger, 'error').mockImplementation() - expect(() => defaultPostHog().capture('$pageview')).not.toThrow() - expect(logger.error).toHaveBeenCalledWith('You must initialize PostHog before calling posthog.capture') + expect(mockLogger.uninitializedWarning).toHaveBeenCalledWith('posthog.capture') }) }) @@ -1112,8 +1107,6 @@ describe('posthog core', () => { }) it('handles loaded config option throwing gracefully', () => { - jest.spyOn(logger, 'critical').mockImplementation() - const posthog = posthogWith( { loaded: () => { @@ -1133,7 +1126,7 @@ describe('posthog core', () => { posthog._loaded() - expect(logger.critical).toHaveBeenCalledWith('`loaded` function failed', expect.anything()) + expect(mockLogger.critical).toHaveBeenCalledWith('`loaded` function failed', expect.anything()) }) describe('/decide', () => { diff --git a/src/__tests__/rate-limiter.test.ts b/src/__tests__/rate-limiter.test.ts index 67455478d..81fcb96c9 100644 --- a/src/__tests__/rate-limiter.test.ts +++ b/src/__tests__/rate-limiter.test.ts @@ -1,8 +1,6 @@ +import { clearLoggerMocks, mockLogger } from './helpers/mock-logger' import { window } from '../../src/utils/globals' import { RateLimiter } from '../rate-limiter' -import { logger } from '../utils/logger' - -jest.mock('../../src/utils/logger') describe('Rate Limiter', () => { let rateLimiter: RateLimiter @@ -44,6 +42,8 @@ describe('Rate Limiter', () => { } rateLimiter = new RateLimiter(mockPostHog as any) + + clearLoggerMocks() }) describe('client side', () => { @@ -270,7 +270,7 @@ describe('Rate Limiter', () => { text: '', }) - expect(jest.mocked(logger).error).not.toHaveBeenCalled() + expect(mockLogger.error).not.toHaveBeenCalled() }) }) }) diff --git a/src/__tests__/site-apps.ts b/src/__tests__/site-apps.ts index aea6407a5..a1f1d6bd1 100644 --- a/src/__tests__/site-apps.ts +++ b/src/__tests__/site-apps.ts @@ -1,19 +1,14 @@ +import { mockLogger } from './helpers/mock-logger' + import { SiteApps } from '../site-apps' import { PostHogPersistence } from '../posthog-persistence' import { RequestRouter } from '../utils/request-router' import { PostHog } from '../posthog-core' import { DecideResponse, PostHogConfig, Properties, CaptureResult } from '../types' import { assignableWindow } from '../utils/globals' -import { logger } from '../utils/logger' import '../entrypoints/external-scripts-loader' import { isFunction } from '../utils/type-utils' -jest.mock('../utils/logger', () => ({ - logger: { - error: jest.fn(), - }, -})) - describe('SiteApps', () => { let posthog: PostHog let siteAppsInstance: SiteApps @@ -314,8 +309,8 @@ describe('SiteApps', () => { siteAppsInstance.onRemoteConfig(response) - expect(logger.error).toHaveBeenCalledWith( - 'PostHog site apps are disabled. Enable the "opt_in_site_apps" config to proceed.' + expect(mockLogger.error).toHaveBeenCalledWith( + 'Site apps exist but "opt_in_site_apps" is not set so they are not loaded.' ) expect(siteAppsInstance.loaded).toBe(true) }) diff --git a/src/__tests__/utils/number-utils.test.ts b/src/__tests__/utils/number-utils.test.ts index 0c6c6cd20..872105a44 100644 --- a/src/__tests__/utils/number-utils.test.ts +++ b/src/__tests__/utils/number-utils.test.ts @@ -1,11 +1,6 @@ -import { clampToRange } from '../../utils/number-utils' -import { logger } from '../../utils/logger' +import { mockLogger } from '../helpers/mock-logger' -jest.mock('../../utils/logger', () => ({ - logger: { - warn: jest.fn(), - }, -})) +import { clampToRange } from '../../utils/number-utils' describe('number-utils', () => { describe('clampToRange', () => { @@ -87,7 +82,7 @@ describe('number-utils', () => { it('logs a warning when min is greater than max', () => { expect(clampToRange(50, 100, 10, 'Test Label')).toBe(10) - expect(logger.warn).toHaveBeenCalledWith('min cannot be greater than max.') + expect(mockLogger.warn).toHaveBeenCalledWith('min cannot be greater than max.') }) }) }) diff --git a/src/autocapture-utils.ts b/src/autocapture-utils.ts index 00ca3883f..49e6d9612 100644 --- a/src/autocapture-utils.ts +++ b/src/autocapture-utils.ts @@ -417,7 +417,7 @@ export function getNestedSpanText(target: Element): string { text = `${text} ${getNestedSpanText(child)}`.trim() } } catch (e) { - logger.error(e) + logger.error('[AutoCapture]', e) } } }) diff --git a/src/autocapture.ts b/src/autocapture.ts index 59feb9172..56cd4e1fd 100644 --- a/src/autocapture.ts +++ b/src/autocapture.ts @@ -20,11 +20,13 @@ import { PostHog } from './posthog-core' import { AUTOCAPTURE_DISABLED_SERVER_SIDE } from './constants' import { isBoolean, isFunction, isNull, isObject } from './utils/type-utils' -import { logger } from './utils/logger' +import { createLogger } from './utils/logger' import { document, window } from './utils/globals' import { convertToURL } from './utils/request-utils' import { isDocumentFragment, isElementNode, isTag, isTextNode } from './utils/element-utils' +const logger = createLogger('[AutoCapture]') + function limitText(length: number, text: string): string { if (text.length > length) { return text.slice(0, length) + '...' diff --git a/src/decide.ts b/src/decide.ts index f0cd3c07a..9483e4d20 100644 --- a/src/decide.ts +++ b/src/decide.ts @@ -2,9 +2,11 @@ import { PostHog } from './posthog-core' import { Compression, DecideResponse, RemoteConfig } from './types' import { STORED_GROUP_PROPERTIES_KEY, STORED_PERSON_PROPERTIES_KEY } from './constants' -import { logger } from './utils/logger' +import { createLogger } from './utils/logger' import { assignableWindow, document } from './utils/globals' +const logger = createLogger('[Decide]') + export class Decide { constructor(private readonly instance: PostHog) { // don't need to wait for `decide` to return if flags were provided on initialisation diff --git a/src/entrypoints/exception-autocapture.ts b/src/entrypoints/exception-autocapture.ts index 07dd05bad..8b4516322 100644 --- a/src/entrypoints/exception-autocapture.ts +++ b/src/entrypoints/exception-autocapture.ts @@ -1,7 +1,9 @@ import { errorToProperties, unhandledRejectionToProperties } from '../extensions/exception-autocapture/error-conversion' import { assignableWindow, window } from '../utils/globals' import { ErrorEventArgs, Properties } from '../types' -import { logger } from '../utils/logger' +import { createLogger } from '../utils/logger' + +const logger = createLogger('[ExceptionAutocapture]') const wrapOnError = (captureFn: (props: Properties) => void) => { const win = window as any diff --git a/src/entrypoints/external-scripts-loader.ts b/src/entrypoints/external-scripts-loader.ts index 32489b25d..6d3a0441c 100644 --- a/src/entrypoints/external-scripts-loader.ts +++ b/src/entrypoints/external-scripts-loader.ts @@ -1,6 +1,8 @@ import type { PostHog } from '../posthog-core' import { assignableWindow, document, PostHogExtensionKind } from '../utils/globals' -import { logger } from '../utils/logger' +import { createLogger } from '../utils/logger' + +const logger = createLogger('[ExternalScriptsLoader]') const loadScript = (posthog: PostHog, url: string, callback: (error?: string | Event, event?: Event) => void) => { if (posthog.config.disable_external_dependency_loading) { diff --git a/src/entrypoints/recorder.ts b/src/entrypoints/recorder.ts index ffda9496a..cade379f9 100644 --- a/src/entrypoints/recorder.ts +++ b/src/entrypoints/recorder.ts @@ -22,13 +22,15 @@ import { isString, isUndefined, } from '../utils/type-utils' -import { logger } from '../utils/logger' +import { createLogger } from '../utils/logger' import { assignableWindow } from '../utils/globals' import { defaultNetworkOptions } from '../extensions/replay/config' import { formDataToQuery } from '../utils/request-utils' import { patch } from '../extensions/replay/rrweb-plugins/patch' import { isHostOnDenyList } from '../extensions/replay/external/denylist' +const logger = createLogger('[Recorder]') + export type NetworkData = { requests: CapturedNetworkRequest[] isInitial?: boolean diff --git a/src/extensions/dead-clicks-autocapture.ts b/src/extensions/dead-clicks-autocapture.ts index 1c4d1108f..724d4e68f 100644 --- a/src/extensions/dead-clicks-autocapture.ts +++ b/src/extensions/dead-clicks-autocapture.ts @@ -2,10 +2,10 @@ import { PostHog } from '../posthog-core' import { DEAD_CLICKS_ENABLED_SERVER_SIDE } from '../constants' import { isBoolean, isObject } from '../utils/type-utils' import { assignableWindow, document, LazyLoadedDeadClicksAutocaptureInterface } from '../utils/globals' -import { logger } from '../utils/logger' +import { createLogger } from '../utils/logger' import { DeadClicksAutoCaptureConfig, RemoteConfig } from '../types' -const LOGGER_PREFIX = '[Dead Clicks]' +const logger = createLogger('[Dead Clicks]') export const isDeadClicksEnabledForHeatmaps = () => { return true @@ -58,7 +58,7 @@ export class DeadClicksAutocapture { 'dead-clicks-autocapture', (err) => { if (err) { - logger.error(LOGGER_PREFIX + ' failed to load script', err) + logger.error('failed to load script', err) return } cb() @@ -68,7 +68,7 @@ export class DeadClicksAutocapture { private start() { if (!document) { - logger.error(LOGGER_PREFIX + ' `document` not found. Cannot start.') + logger.error('`document` not found. Cannot start.') return } @@ -86,7 +86,7 @@ export class DeadClicksAutocapture { config ) this._lazyLoadedDeadClicksAutocapture.start(document) - logger.info(`${LOGGER_PREFIX} starting...`) + logger.info(`starting...`) } } @@ -94,7 +94,7 @@ export class DeadClicksAutocapture { if (this._lazyLoadedDeadClicksAutocapture) { this._lazyLoadedDeadClicksAutocapture.stop() this._lazyLoadedDeadClicksAutocapture = undefined - logger.info(`${LOGGER_PREFIX} stopping...`) + logger.info(`stopping...`) } } } diff --git a/src/extensions/exception-autocapture/index.ts b/src/extensions/exception-autocapture/index.ts index 71e683cb0..bb166bb4c 100644 --- a/src/extensions/exception-autocapture/index.ts +++ b/src/extensions/exception-autocapture/index.ts @@ -2,10 +2,10 @@ import { assignableWindow, window } from '../../utils/globals' import { PostHog } from '../../posthog-core' import { Properties, RemoteConfig } from '../../types' -import { logger } from '../../utils/logger' +import { createLogger } from '../../utils/logger' import { EXCEPTION_CAPTURE_ENABLED_SERVER_SIDE } from '../../constants' -const LOGGER_PREFIX = '[Exception Autocapture]' +const logger = createLogger('[ExceptionAutocapture]') export class ExceptionObserver { instance: PostHog @@ -35,7 +35,7 @@ export class ExceptionObserver { startIfEnabled(): void { if (this.isEnabled && !this.isCapturing) { - logger.info(LOGGER_PREFIX + ' enabled, starting...') + logger.info('enabled, starting...') this.loadScript(this.startCapturing) } } @@ -51,7 +51,7 @@ export class ExceptionObserver { 'exception-autocapture', (err) => { if (err) { - return logger.error(LOGGER_PREFIX + ' failed to load script', err) + return logger.error('failed to load script', err) } cb() } @@ -68,7 +68,7 @@ export class ExceptionObserver { assignableWindow.__PosthogExtensions__?.errorWrappingFunctions?.wrapUnhandledRejection if (!wrapOnError || !wrapUnhandledRejection) { - logger.error(LOGGER_PREFIX + ' failed to load error wrapping functions - cannot start') + logger.error('failed to load error wrapping functions - cannot start') return } @@ -76,7 +76,7 @@ export class ExceptionObserver { this.unwrapOnError = wrapOnError(this.captureException.bind(this)) this.unwrapUnhandledRejection = wrapUnhandledRejection(this.captureException.bind(this)) } catch (e) { - logger.error(LOGGER_PREFIX + ' failed to start', e) + logger.error('failed to start', e) this.stopCapturing() } } diff --git a/src/extensions/replay/config.ts b/src/extensions/replay/config.ts index d4bc96c4f..6ed58c1b7 100644 --- a/src/extensions/replay/config.ts +++ b/src/extensions/replay/config.ts @@ -6,6 +6,7 @@ import { shouldCaptureValue } from '../../autocapture-utils' import { each } from '../../utils' const LOGGER_PREFIX = '[SessionRecording]' + const REDACTED = 'redacted' export const defaultNetworkOptions: Required = { diff --git a/src/extensions/replay/sessionrecording.ts b/src/extensions/replay/sessionrecording.ts index f36cbfea3..030501aab 100644 --- a/src/extensions/replay/sessionrecording.ts +++ b/src/extensions/replay/sessionrecording.ts @@ -38,7 +38,7 @@ import { } from '@rrweb/types' import { isBoolean, isFunction, isNullish, isNumber, isObject, isString, isUndefined } from '../../utils/type-utils' -import { logger } from '../../utils/logger' +import { createLogger } from '../../utils/logger' import { assignableWindow, document, PostHogExtensionKind, window } from '../../utils/globals' import { buildNetworkRequestOptions } from './config' import { isLocalhost } from '../../utils/request-utils' @@ -47,6 +47,9 @@ import { gzipSync, strFromU8, strToU8 } from 'fflate' import { clampToRange } from '../../utils/number-utils' import { includes } from '../../utils' +const LOGGER_PREFIX = '[SessionRecording]' +const logger = createLogger(LOGGER_PREFIX) + type SessionStartReason = | 'sampling_overridden' | 'recording_initialized' @@ -119,8 +122,6 @@ const newQueuedEvent = (rrwebMethod: () => void): QueuedRRWebEvent => ({ attempt: 1, }) -const LOGGER_PREFIX = '[SessionRecording]' - type compressedFullSnapshotEvent = { type: EventType.FullSnapshot data: string @@ -207,7 +208,7 @@ function compressEvent(event: eventWithTime): eventWithTime | compressedEventWit } } } catch (e) { - logger.error(LOGGER_PREFIX + ' could not compress event - will use uncompressed event', e) + logger.error('could not compress event - will use uncompressed event', e) } return event } @@ -445,7 +446,7 @@ export class SessionRecording { this.receivedDecide = false if (!this.instance.sessionManager) { - logger.error(LOGGER_PREFIX + ' started without valid sessionManager') + logger.error('started without valid sessionManager') throw new Error(LOGGER_PREFIX + ' started without valid sessionManager. This is a bug.') } @@ -458,8 +459,7 @@ export class SessionRecording { if (this.sessionIdleThresholdMilliseconds >= this.sessionManager.sessionTimeoutMs) { logger.warn( - LOGGER_PREFIX + - ` session_idle_threshold_ms (${this.sessionIdleThresholdMilliseconds}) is greater than the session timeout (${this.sessionManager.sessionTimeoutMs}). Session will never be detected as idle` + `session_idle_threshold_ms (${this.sessionIdleThresholdMilliseconds}) is greater than the session timeout (${this.sessionManager.sessionTimeoutMs}). Session will never be detected as idle` ) } } @@ -559,7 +559,7 @@ export class SessionRecording { this._samplingSessionListener?.() this._samplingSessionListener = undefined - logger.info(LOGGER_PREFIX + ' stopped') + logger.info('stopped') } } @@ -601,8 +601,7 @@ export class SessionRecording { this._reportStarted('sampled') } else { logger.warn( - LOGGER_PREFIX + - ` Sample rate (${currentSampleRate}) has determined that this sessionId (${sessionId}) will not be sent to the server.` + `Sample rate (${currentSampleRate}) has determined that this sessionId (${sessionId}) will not be sent to the server.` ) } @@ -756,7 +755,7 @@ export class SessionRecording { if (!this.rrwebRecord) { assignableWindow.__PosthogExtensions__?.loadExternalDependency?.(this.instance, this.scriptName, (err) => { if (err) { - return logger.error(LOGGER_PREFIX + ` could not load recorder`, err) + return logger.error('could not load recorder', err) } this._onScriptLoaded() @@ -765,7 +764,7 @@ export class SessionRecording { this._onScriptLoaded() } - logger.info(LOGGER_PREFIX + ' starting') + logger.info('starting') if (this.status === 'active') { this._reportStarted(startReason || 'recording_initialized') } @@ -868,7 +867,7 @@ export class SessionRecording { rrwebMethod: queuedRRWebEvent.rrwebMethod, }) } else { - logger.warn(LOGGER_PREFIX + ' could not emit queued rrweb event.', e, queuedRRWebEvent) + logger.warn('could not emit queued rrweb event.', e, queuedRRWebEvent) } return false @@ -926,8 +925,7 @@ export class SessionRecording { if (!this.rrwebRecord) { logger.error( - LOGGER_PREFIX + - 'onScriptLoaded was called but rrwebRecord is not available. This indicates something has gone wrong.' + 'onScriptLoaded was called but rrwebRecord is not available. This indicates something has gone wrong.' ) return } @@ -1006,7 +1004,7 @@ export class SessionRecording { networkPlugin(buildNetworkRequestOptions(this.instance.config, this.networkPayloadCapture)) ) } else { - logger.info(LOGGER_PREFIX + ' NetworkCapture not started because we are on localhost.') + logger.info('NetworkCapture not started because we are on localhost.') } } @@ -1276,7 +1274,7 @@ export class SessionRecording { this._flushBuffer() }, 100) - logger.info(LOGGER_PREFIX + ' recording paused due to URL blocker') + logger.info('recording paused due to URL blocker') this._tryAddCustomEvent('recording paused', { reason: 'url blocker' }) } @@ -1292,7 +1290,7 @@ export class SessionRecording { this._scheduleFullSnapshot() this._tryAddCustomEvent('recording resumed', { reason: 'left blocked url' }) - logger.info(LOGGER_PREFIX + ' recording resumed') + logger.info('recording resumed') } private _addEventTriggerListener() { @@ -1308,7 +1306,7 @@ export class SessionRecording { this._activateTrigger('event') } } catch (e) { - logger.error(LOGGER_PREFIX + 'Could not activate event trigger', e) + logger.error('Could not activate event trigger', e) } }) } @@ -1352,7 +1350,7 @@ export class SessionRecording { this.instance.register_for_session({ $session_recording_start_reason: startReason, }) - logger.info(LOGGER_PREFIX + ' ' + startReason.replace('_', ' '), tagPayload) + logger.info(startReason.replace('_', ' '), tagPayload) if (!includes(['recording_initialized', 'session_id_changed'], startReason)) { this._tryAddCustomEvent(startReason, tagPayload) } diff --git a/src/extensions/segment-integration.ts b/src/extensions/segment-integration.ts index c35b016a4..e243afd3e 100644 --- a/src/extensions/segment-integration.ts +++ b/src/extensions/segment-integration.ts @@ -17,12 +17,14 @@ * ``` */ import { PostHog } from '../posthog-core' -import { logger } from '../utils/logger' +import { createLogger } from '../utils/logger' import { uuidv7 } from '../uuidv7' import { isFunction } from '../utils/type-utils' import { USER_STATE } from '../constants' +const logger = createLogger('[SegmentIntegration]') + export type SegmentUser = { anonymousId(): string | undefined id(): string | undefined @@ -72,11 +74,11 @@ const createSegmentIntegration = (posthog: PostHog): SegmentPlugin => { } if (!ctx.event.userId && ctx.event.anonymousId !== posthog.get_distinct_id()) { // This is our only way of detecting that segment's analytics.reset() has been called so we also call it - logger.info('Segment integration does not have a userId set, resetting PostHog') + logger.info('No userId set, resetting PostHog') posthog.reset() } if (ctx.event.userId && ctx.event.userId !== posthog.get_distinct_id()) { - logger.info('Segment integration has a userId set, identifying with PostHog') + logger.info('UserId set, identifying with PostHog') posthog.identify(ctx.event.userId) } diff --git a/src/extensions/surveys.tsx b/src/extensions/surveys.tsx index f3ee53e50..b1fec5638 100644 --- a/src/extensions/surveys.tsx +++ b/src/extensions/surveys.tsx @@ -32,8 +32,9 @@ import { RatingQuestion, MultipleChoiceQuestion, } from './surveys/components/QuestionTypes' -import { logger } from '../utils/logger' import { Cancel } from './surveys/components/QuestionHeader' +import { createLogger } from '../utils/logger' +const logger = createLogger('[Surveys]') // We cast the types here which is dangerous but protected by the top level generateSurveys call const window = _window as Window & typeof globalThis diff --git a/src/extensions/toolbar.ts b/src/extensions/toolbar.ts index bf13d0ae7..666dc041b 100644 --- a/src/extensions/toolbar.ts +++ b/src/extensions/toolbar.ts @@ -160,7 +160,7 @@ export class Toolbar { assignableWindow.__PosthogExtensions__?.loadExternalDependency?.(this.instance, 'toolbar', (err) => { if (err) { - logger.error('Failed to load toolbar', err) + logger.error('[Toolbar] Failed to load', err) this.setToolbarState(ToolbarState.UNINITIALIZED) return } diff --git a/src/extensions/tracing-headers.ts b/src/extensions/tracing-headers.ts index 4ce7864de..b8867af5c 100644 --- a/src/extensions/tracing-headers.ts +++ b/src/extensions/tracing-headers.ts @@ -1,9 +1,9 @@ import { PostHog } from '../posthog-core' import { assignableWindow } from '../utils/globals' -import { logger } from '../utils/logger' +import { createLogger } from '../utils/logger' import { isUndefined } from '../utils/type-utils' -const LOGGER_PREFIX = '[TRACING-HEADERS]' +const logger = createLogger('[TracingHeaders]') export class TracingHeaders { private _restoreXHRPatch: (() => void) | undefined = undefined @@ -19,7 +19,7 @@ export class TracingHeaders { assignableWindow.__PosthogExtensions__?.loadExternalDependency?.(this.instance, 'tracing-headers', (err) => { if (err) { - return logger.error(LOGGER_PREFIX + ' failed to load script', err) + return logger.error('failed to load script', err) } cb() }) diff --git a/src/extensions/web-vitals/index.ts b/src/extensions/web-vitals/index.ts index ccea6a4df..5bb850c1c 100644 --- a/src/extensions/web-vitals/index.ts +++ b/src/extensions/web-vitals/index.ts @@ -1,17 +1,18 @@ import { PostHog } from '../../posthog-core' import { RemoteConfig, SupportedWebVitalsMetrics } from '../../types' -import { logger } from '../../utils/logger' +import { createLogger } from '../../utils/logger' import { isBoolean, isNullish, isNumber, isObject, isUndefined } from '../../utils/type-utils' import { WEB_VITALS_ALLOWED_METRICS, WEB_VITALS_ENABLED_SERVER_SIDE } from '../../constants' import { assignableWindow, window } from '../../utils/globals' +const logger = createLogger('[Web Vitals]') + type WebVitalsMetricCallback = (metric: any) => void export const DEFAULT_FLUSH_TO_CAPTURE_TIMEOUT_MILLISECONDS = 5000 const ONE_MINUTE_IN_MILLIS = 60 * 1000 export const FIFTEEN_MINUTES_IN_MILLIS = 15 * ONE_MINUTE_IN_MILLIS -const LOGGER_PREFIX = '[Web Vitals]' type WebVitalsEventBuffer = { url: string | undefined; metrics: any[]; firstMetricTimestamp: number | undefined } export class WebVitalsAutocapture { @@ -65,7 +66,7 @@ export class WebVitalsAutocapture { public startIfEnabled(): void { if (this.isEnabled && !this._initialized) { - logger.info(LOGGER_PREFIX + ' enabled, starting...') + logger.info('enabled, starting...') this.loadScript(this._startCapturing) } } @@ -99,7 +100,7 @@ export class WebVitalsAutocapture { } assignableWindow.__PosthogExtensions__?.loadExternalDependency?.(this.instance, 'web-vitals', (err) => { if (err) { - logger.error(LOGGER_PREFIX + ' failed to load script', err) + logger.error('failed to load script', err) return } cb() @@ -110,7 +111,7 @@ export class WebVitalsAutocapture { // TODO you should be able to mask the URL here const href = window ? window.location.href : undefined if (!href) { - logger.error(LOGGER_PREFIX + 'Could not determine current URL') + logger.error('Could not determine current URL') } return href } @@ -139,7 +140,7 @@ export class WebVitalsAutocapture { private _addToBuffer = (metric: any) => { const sessionIds = this.instance.sessionManager?.checkAndGetSessionAndWindowId(true) if (isUndefined(sessionIds)) { - logger.error(LOGGER_PREFIX + 'Could not read session ID. Dropping metrics!') + logger.error('Could not read session ID. Dropping metrics!') return } @@ -151,14 +152,14 @@ export class WebVitalsAutocapture { } if (isNullish(metric?.name) || isNullish(metric?.value)) { - logger.error(LOGGER_PREFIX + 'Invalid metric received', metric) + logger.error('Invalid metric received', metric) return } // we observe some very large values sometimes, we'll ignore them // since the likelihood of LCP > 1 hour being correct is very low if (this._maxAllowedValue && metric.value >= this._maxAllowedValue) { - logger.error(LOGGER_PREFIX + 'Ignoring metric with value >= ' + this._maxAllowedValue, metric) + logger.error('Ignoring metric with value >= ' + this._maxAllowedValue, metric) return } @@ -215,7 +216,7 @@ export class WebVitalsAutocapture { } if (!onLCP || !onCLS || !onFCP || !onINP) { - logger.error(LOGGER_PREFIX + 'web vitals callbacks not loaded - not starting') + logger.error('web vitals callbacks not loaded - not starting') return } diff --git a/src/heatmaps.ts b/src/heatmaps.ts index e94400220..52b30c45d 100644 --- a/src/heatmaps.ts +++ b/src/heatmaps.ts @@ -7,13 +7,13 @@ import { document, window } from './utils/globals' import { getEventTarget, getParentElement } from './autocapture-utils' import { HEATMAPS_ENABLED_SERVER_SIDE } from './constants' import { isEmptyObject, isObject, isUndefined } from './utils/type-utils' -import { logger } from './utils/logger' +import { createLogger } from './utils/logger' import { isElementInToolbar, isElementNode, isTag } from './utils/element-utils' import { DeadClicksAutocapture, isDeadClicksEnabledForHeatmaps } from './extensions/dead-clicks-autocapture' const DEFAULT_FLUSH_INTERVAL = 5000 -const HEATMAPS = 'heatmaps' -const LOGGER_PREFIX = '[' + HEATMAPS + ']' + +const logger = createLogger('[Heatmaps]') type HeatmapEventBuffer = | { @@ -89,7 +89,7 @@ export class Heatmaps { if (this._initialized) { return } - logger.info(LOGGER_PREFIX + ' starting...') + logger.info('starting...') this._setupListeners() this._flushInterval = setInterval(this.flush.bind(this), this.flushIntervalMilliseconds) } else { diff --git a/src/posthog-core.ts b/src/posthog-core.ts index 3e8080839..b885fd98e 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -412,7 +412,7 @@ export class PostHog { ) if (this.config.on_xhr_error) { - logger.error('[posthog] on_xhr_error is deprecated. Use on_request_error instead') + logger.error('on_xhr_error is deprecated. Use on_request_error instead') } this.compression = config.disable_compression ? undefined : Compression.GZipJS diff --git a/src/posthog-featureflags.ts b/src/posthog-featureflags.ts index 04f62c4c8..5adc3315c 100644 --- a/src/posthog-featureflags.ts +++ b/src/posthog-featureflags.ts @@ -20,7 +20,9 @@ import { } from './constants' import { isArray } from './utils/type-utils' -import { logger } from './utils/logger' +import { createLogger } from './utils/logger' + +const logger = createLogger('[FeatureFlags]') const PERSISTENCE_ACTIVE_FEATURE_FLAGS = '$active_feature_flags' const PERSISTENCE_OVERRIDE_FEATURE_FLAGS = '$override_feature_flags' diff --git a/src/posthog-surveys.ts b/src/posthog-surveys.ts index 9476bb936..f33fe4f4a 100644 --- a/src/posthog-surveys.ts +++ b/src/posthog-surveys.ts @@ -11,11 +11,11 @@ import { isUrlMatchingRegex } from './utils/request-utils' import { SurveyEventReceiver } from './utils/survey-event-receiver' import { assignableWindow, document, window } from './utils/globals' import { RemoteConfig } from './types' -import { logger } from './utils/logger' +import { createLogger } from './utils/logger' import { isNullish } from './utils/type-utils' import { getSurveySeenStorageKeys } from './extensions/surveys/surveys-utils' -const LOGGER_PREFIX = '[Surveys]' +const logger = createLogger('[Surveys]') export const surveyUrlValidationMap: Record boolean> = { icontains: (conditionsUrl) => @@ -90,7 +90,7 @@ export class PostHogSurveys { assignableWindow.__PosthogExtensions__?.loadExternalDependency?.(this.instance, 'surveys', (err) => { if (err) { - return logger.error(LOGGER_PREFIX, 'Could not load surveys script', err) + return logger.error('Could not load surveys script', err) } this._surveyManager = assignableWindow.__PosthogExtensions__?.generateSurveys?.(this.instance) @@ -295,14 +295,14 @@ export class PostHogSurveys { return nextQuestionIndex } - logger.warn(LOGGER_PREFIX, 'Falling back to next question index due to unexpected branching type') + logger.warn('Falling back to next question index due to unexpected branching type') return nextQuestionIndex } // this method is lazily loaded onto the window to avoid loading preact and other dependencies if surveys is not enabled private _canActivateRepeatedly(survey: Survey) { if (isNullish(assignableWindow.__PosthogExtensions__?.canActivateRepeatedly)) { - logger.warn(LOGGER_PREFIX, 'canActivateRepeatedly is not defined, must init before calling') + logger.warn('init was not called') return false // TODO does it make sense to have a default here? } return assignableWindow.__PosthogExtensions__.canActivateRepeatedly(survey) @@ -310,7 +310,7 @@ export class PostHogSurveys { canRenderSurvey(surveyId: string) { if (isNullish(this._surveyManager)) { - logger.warn(LOGGER_PREFIX, 'canActivateRepeatedly is not defined, must init before calling') + logger.warn('init was not called') return } this.getSurveys((surveys) => { @@ -321,7 +321,7 @@ export class PostHogSurveys { renderSurvey(surveyId: string, selector: string) { if (isNullish(this._surveyManager)) { - logger.warn(LOGGER_PREFIX, 'canActivateRepeatedly is not defined, must init before calling') + logger.warn('init was not called') return } this.getSurveys((surveys) => { diff --git a/src/rate-limiter.ts b/src/rate-limiter.ts index 8d22f3355..9bc31f872 100644 --- a/src/rate-limiter.ts +++ b/src/rate-limiter.ts @@ -1,7 +1,9 @@ import { CAPTURE_RATE_LIMIT } from './constants' import type { PostHog } from './posthog-core' import { RequestResponse } from './types' -import { logger } from './utils/logger' +import { createLogger } from './utils/logger' + +const logger = createLogger('[RateLimiter]') const ONE_MINUTE_IN_MILLISECONDS = 60 * 1000 const RATE_LIMIT_EVENT = '$$client_ingestion_warning' @@ -96,11 +98,11 @@ export class RateLimiter { const response: CaptureResponse = JSON.parse(text) const quotaLimitedProducts = response.quota_limited || [] quotaLimitedProducts.forEach((batchKey) => { - logger.info(`[RateLimiter] ${batchKey || 'events'} is quota limited.`) + logger.info(`${batchKey || 'events'} is quota limited.`) this.serverLimits[batchKey] = new Date().getTime() + ONE_MINUTE_IN_MILLISECONDS }) } catch (e: any) { - logger.warn(`[RateLimiter] could not rate limit - continuing. Error: "${e?.message}"`, { text }) + logger.warn(`could not rate limit - continuing. Error: "${e?.message}"`, { text }) return } } diff --git a/src/sessionid.ts b/src/sessionid.ts index e0d10bdf4..b9b7c63c0 100644 --- a/src/sessionid.ts +++ b/src/sessionid.ts @@ -6,11 +6,13 @@ import { uuid7ToTimestampMs, uuidv7 } from './uuidv7' import { window } from './utils/globals' import { isArray, isNumber, isUndefined } from './utils/type-utils' -import { logger } from './utils/logger' +import { createLogger } from './utils/logger' import { clampToRange } from './utils/number-utils' import { PostHog } from './posthog-core' +const logger = createLogger('[SessionId]') + export const DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS = 30 * 60 // 30 minutes export const MAX_SESSION_IDLE_TIMEOUT_SECONDS = 10 * 60 * 60 // 10 hours const MIN_SESSION_IDLE_TIMEOUT_SECONDS = 60 // 1 minute @@ -230,7 +232,7 @@ export class SessionIdManager { if (noSessionId || activityTimeout || sessionPastMaximumLength) { sessionId = this._sessionIdGenerator() windowId = this._windowIdGenerator() - logger.info('[SessionId] new session ID generated', { + logger.info('new session ID generated', { sessionId, windowId, changeReason: { noSessionId, activityTimeout, sessionPastMaximumLength }, diff --git a/src/site-apps.ts b/src/site-apps.ts index 63586b0d3..94c8726ae 100644 --- a/src/site-apps.ts +++ b/src/site-apps.ts @@ -1,9 +1,11 @@ import { PostHog } from './posthog-core' import { CaptureResult, RemoteConfig } from './types' import { assignableWindow } from './utils/globals' -import { logger } from './utils/logger' +import { createLogger } from './utils/logger' import { isArray } from './utils/type-utils' +const logger = createLogger('[SiteApps]') + export class SiteApps { instance: PostHog enabled: boolean @@ -102,7 +104,7 @@ export class SiteApps { }) } } else if (response['siteApps'].length > 0) { - logger.error('PostHog site apps are disabled. Enable the "opt_in_site_apps" config to proceed.') + logger.error('Site apps exist but "opt_in_site_apps" is not set so they are not loaded.') this.loaded = true } else { this.loaded = true diff --git a/src/utils/logger.ts b/src/utils/logger.ts index a2bbfc405..c4e527006 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -2,44 +2,62 @@ import Config from '../config' import { isUndefined } from './type-utils' import { assignableWindow, window } from './globals' -const LOGGER_PREFIX = '[PostHog.js]' -export const logger = { - _log: (level: 'log' | 'warn' | 'error', ...args: any[]) => { - if ( - window && - (Config.DEBUG || assignableWindow.POSTHOG_DEBUG) && - !isUndefined(window.console) && - window.console - ) { - const consoleLog = - '__rrweb_original__' in window.console[level] - ? (window.console[level] as any)['__rrweb_original__'] - : window.console[level] +export type Logger = { + _log: (level: 'log' | 'warn' | 'error', ...args: any[]) => void + info: (...args: any[]) => void + warn: (...args: any[]) => void + error: (...args: any[]) => void + critical: (...args: any[]) => void + uninitializedWarning: (methodName: string) => void + createLogger: (prefix: string) => Logger +} + +const _createLogger = (prefix: string): Logger => { + const logger: Logger = { + _log: (level: 'log' | 'warn' | 'error', ...args: any[]) => { + if ( + window && + (Config.DEBUG || assignableWindow.POSTHOG_DEBUG) && + !isUndefined(window.console) && + window.console + ) { + const consoleLog = + '__rrweb_original__' in window.console[level] + ? (window.console[level] as any)['__rrweb_original__'] + : window.console[level] + + // eslint-disable-next-line no-console + consoleLog(prefix, ...args) + } + }, + + info: (...args: any[]) => { + logger._log('log', ...args) + }, + + warn: (...args: any[]) => { + logger._log('warn', ...args) + }, + error: (...args: any[]) => { + logger._log('error', ...args) + }, + + critical: (...args: any[]) => { + // Critical errors are always logged to the console // eslint-disable-next-line no-console - consoleLog(LOGGER_PREFIX, ...args) - } - }, - - info: (...args: any[]) => { - logger._log('log', ...args) - }, - - warn: (...args: any[]) => { - logger._log('warn', ...args) - }, - - error: (...args: any[]) => { - logger._log('error', ...args) - }, - - critical: (...args: any[]) => { - // Critical errors are always logged to the console - // eslint-disable-next-line no-console - console.error(LOGGER_PREFIX, ...args) - }, - - uninitializedWarning: (methodName: string) => { - logger.error(`You must initialize PostHog before calling ${methodName}`) - }, + console.error(prefix, ...args) + }, + + uninitializedWarning: (methodName: string) => { + logger.error(`You must initialize PostHog before calling ${methodName}`) + }, + + createLogger: (additionalPrefix: string) => _createLogger(`${prefix} ${additionalPrefix}`), + } + return logger } + +export const logger = _createLogger('[PostHog.js]') + +export const createLogger = logger.createLogger