-
Notifications
You must be signed in to change notification settings - Fork 4
Logger abstraction added #159
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: refactor/user-manager
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| export type { HawkStorage } from './storages/hawk-storage'; | ||
| export type { UserManager } from './users/user-manager'; | ||
| export { HawkStorageUserManager } from './users/hawk-storage-user-manager'; | ||
| export type { Logger, LogType } from './logger/logger'; | ||
| export { setLogger, log } from './logger/logger'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| /** | ||
| * Log level type for categorizing log messages. | ||
| * | ||
| * Includes standard console methods supported in both browser and Node.js: | ||
| * - Standard levels: `log`, `warn`, `error`, `info` | ||
| * - Performance timing: `time`, `timeEnd` | ||
| */ | ||
| export type LogType = 'log' | 'warn' | 'error' | 'info' | 'time' | 'timeEnd'; | ||
|
|
||
| /** | ||
| * Logger function interface for environment-specific logging implementations. | ||
| * | ||
| * Implementations should handle message formatting, output styling, | ||
| * and platform-specific logging mechanisms (e.g., console, file, network). | ||
| * | ||
| * @param msg - The message to log. | ||
| * @param type - Log level/severity (default: 'log'). | ||
| * @param args - Additional data to include with the log message. | ||
| */ | ||
| export interface Logger { | ||
| (msg: string, type?: LogType, args?: unknown): void; | ||
| } | ||
|
|
||
| /** | ||
| * Global logger instance, set by environment-specific packages. | ||
| */ | ||
| let loggerInstance: Logger | null = null; | ||
|
|
||
| /** | ||
| * Registers the environment-specific logger implementation. | ||
| * | ||
| * This should be called once during application initialization | ||
| * by the environment-specific package. | ||
| * | ||
| * @param logger - Logger implementation to use globally. | ||
| */ | ||
| export function setLogger(logger: Logger): void { | ||
| loggerInstance = logger; | ||
| } | ||
|
|
||
| /** | ||
| * Logs a message using the registered logger implementation. | ||
| * | ||
| * If no logger has been registered via {@link setLogger}, this is a no-op. | ||
| * | ||
| * @param msg - Message to log. | ||
| * @param type - Log level (default: 'log'). | ||
| * @param args - Additional arguments to log. | ||
| */ | ||
| export function log(msg: string, type?: LogType, args?: unknown): void { | ||
| if (loggerInstance) { | ||
| loggerInstance(msg, type, args); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,6 +1,5 @@ | ||||||
| import Socket from './modules/socket'; | ||||||
| import Sanitizer from './modules/sanitizer'; | ||||||
| import log from './utils/log'; | ||||||
| import StackParser from './modules/stackParser'; | ||||||
| import type { CatcherMessage, HawkInitialSettings, BreadcrumbsAPI, Transport } from './types'; | ||||||
| import { VueIntegration } from './integrations/vue'; | ||||||
|
|
@@ -19,8 +18,9 @@ import { ConsoleCatcher } from './addons/consoleCatcher'; | |||||
| import { BreadcrumbManager } from './addons/breadcrumbs'; | ||||||
| import { validateUser, validateContext, isValidEventPayload } from './utils/validation'; | ||||||
| import type { UserManager } from '@hawk.so/core'; | ||||||
| import { HawkStorageUserManager } from '@hawk.so/core'; | ||||||
| import { HawkStorageUserManager, setLogger, log } from '@hawk.so/core'; | ||||||
| import { HawkLocalStorage } from './storages/hawk-local-storage'; | ||||||
| import { createBrowserLogger } from './logger/logger'; | ||||||
| import { id } from './utils/id'; | ||||||
|
|
||||||
| /** | ||||||
|
|
@@ -120,6 +120,8 @@ export default class Catcher { | |||||
| * @param {HawkInitialSettings|string} settings - If settings is a string, it means an Integration Token | ||||||
| */ | ||||||
| constructor(settings: HawkInitialSettings | string) { | ||||||
| setLogger(createBrowserLogger(VERSION)); | ||||||
|
||||||
|
|
||||||
| if (typeof settings === 'string') { | ||||||
| settings = { | ||||||
| token: settings, | ||||||
|
|
@@ -517,7 +519,7 @@ export default class Catcher { | |||||
| private getIntegrationId(): string { | ||||||
| try { | ||||||
| const decodedIntegrationToken: DecodedIntegrationToken = JSON.parse(atob(this.token)); | ||||||
| const {integrationId} = decodedIntegrationToken; | ||||||
| const { integrationId } = decodedIntegrationToken; | ||||||
|
||||||
| const { integrationId } = decodedIntegrationToken; | |
| const {integrationId} = decodedIntegrationToken; |
Copilot
AI
Feb 17, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This formatting change (adding spaces inside object destructuring) appears to be unrelated to the logger abstraction changes and is a minor style adjustment. While it improves consistency with modern JavaScript style conventions, it would be better to keep such formatting changes separate from functional changes in a PR, or apply them consistently throughout the file if they're part of a deliberate style update.
| const newUser: AffectedUser = { id: id() }; | |
| const newUser: AffectedUser = {id: id()}; |
Copilot
AI
Feb 17, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This formatting change (adding spaces inside object destructuring) appears to be unrelated to the logger abstraction changes and is a minor style adjustment. While it improves consistency with modern JavaScript style conventions, it would be better to keep such formatting changes separate from functional changes in a PR, or apply them consistently throughout the file if they're part of a deliberate style update.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,61 @@ | ||||||
| import type { Logger, LogType } from '@hawk.so/core'; | ||||||
|
|
||||||
| /** | ||||||
| * Creates a browser console logger with Hawk branding and styled output. | ||||||
| * | ||||||
| * The logger outputs to `window.console` with a dark label badge | ||||||
| * containing the Hawk version. Messages are formatted with CSS | ||||||
| * styling for better visibility in browser developer tools. | ||||||
| * | ||||||
| * @param version - Version string to display in log messages. | ||||||
| * @param style - Optional CSS style for the message text (default: 'color: inherit'). | ||||||
| * @returns {Logger} Logger function implementation for browser environments. | ||||||
| * | ||||||
| * @example | ||||||
| * ```TypeScript | ||||||
| * import { createBrowserLogger } from '@hawk.so/browser'; | ||||||
|
||||||
| * import { createBrowserLogger } from '@hawk.so/browser'; | |
| * import { createBrowserLogger } from '@hawk.so/javascript'; |
Copilot
AI
Feb 17, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CSS style string contains duplicate 'line-height: 1em;' properties on lines 33 and 36. While this doesn't cause an error, the second declaration will override the first, making the first one redundant. Consider removing one of the duplicate declarations to clean up the code.
| line-height: 1em; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| import log from './log'; | ||
| import { log } from '@hawk.so/core'; | ||
|
|
||
| /** | ||
| * Symbol to mark error as processed by Hawk | ||
|
|
||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| import { beforeEach, afterEach, describe, it, expect, vi } from 'vitest'; | ||
| import { createBrowserLogger } from '../../src/logger/logger'; | ||
|
|
||
| describe('createBrowserLogger', () => { | ||
| let consoleLogSpy: ReturnType<typeof vi.spyOn>; | ||
| let consoleWarnSpy: ReturnType<typeof vi.spyOn>; | ||
| let consoleErrorSpy: ReturnType<typeof vi.spyOn>; | ||
|
|
||
| beforeEach(() => { | ||
| consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); | ||
| consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); | ||
| consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| vi.restoreAllMocks(); | ||
| }); | ||
|
|
||
| it('should log message with default type', () => { | ||
| const logger = createBrowserLogger('1.0.0'); | ||
|
|
||
| logger('Test message'); | ||
|
|
||
| expect(consoleLogSpy).toHaveBeenCalledWith( | ||
| '%cHawk (1.0.0)%c Test message', | ||
| expect.stringContaining('background-color'), | ||
| 'color: inherit' | ||
| ); | ||
| }); | ||
|
|
||
| it('should log message with specified type', () => { | ||
| const logger = createBrowserLogger('2.0.0'); | ||
|
|
||
| logger('Warning message', 'warn'); | ||
|
|
||
| expect(consoleWarnSpy).toHaveBeenCalledWith( | ||
| '%cHawk (2.0.0)%c Warning message', | ||
| expect.stringContaining('background-color'), | ||
| 'color: inherit' | ||
| ); | ||
| }); | ||
|
|
||
| it('should log error with args', () => { | ||
| const logger = createBrowserLogger('3.0.0'); | ||
| const errorObj = new Error('Test error'); | ||
|
|
||
| logger('Error occurred', 'error', errorObj); | ||
|
|
||
| expect(consoleErrorSpy).toHaveBeenCalledWith( | ||
| '%cHawk (3.0.0)%c Error occurred %o', | ||
| expect.stringContaining('background-color'), | ||
| 'color: inherit', | ||
| errorObj | ||
| ); | ||
| }); | ||
|
|
||
| it('should handle time/timeEnd types', () => { | ||
| const consoleTimeSpy = vi.spyOn(console, 'time').mockImplementation(() => {}); | ||
| const logger = createBrowserLogger('4.0.0'); | ||
|
|
||
| logger('Timer started', 'time'); | ||
|
|
||
| expect(consoleTimeSpy).toHaveBeenCalledWith( | ||
| expect.stringContaining('Hawk (4.0.0)') | ||
| ); | ||
|
|
||
| consoleTimeSpy.mockRestore(); | ||
| }); | ||
|
|
||
| it('should not throw when console method is unavailable', () => { | ||
| const logger = createBrowserLogger('5.0.0'); | ||
|
|
||
| expect(() => { | ||
| // @ts-expect-error - testing invalid type | ||
| logger('Test', 'invalidType'); | ||
| }).not.toThrow(); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The core logger abstraction (setLogger and log functions in @hawk.so/core) lacks test coverage. While the browser-specific implementation (createBrowserLogger) has comprehensive tests, the core abstraction functions are not tested. Consider adding tests to verify that: 1) log is a no-op when no logger is set, 2) setLogger correctly registers a logger, 3) log correctly delegates to the registered logger, and 4) the logger can be replaced by calling setLogger again.