Skip to content
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

Add a Proper Logging Framework #121

Open
dbudzins opened this issue Jul 20, 2022 · 9 comments
Open

Add a Proper Logging Framework #121

dbudzins opened this issue Jul 20, 2022 · 9 comments

Comments

@dbudzins
Copy link
Contributor

We are mostly just using the logDev method everywhere. We should really add a logging framework with an adjustable log level.

dbudzins pushed a commit that referenced this issue Mar 15, 2024
* chore: add pr deployment previews workflows

* fix(payment): redirect to wrong media after payment

* chore: add version number to footer text

Co-authored-by: Melissa Hart <48496458+MelissaDTH@users.noreply.github.com>

* fix: show error on email field when invalid

* fix(project): favicons & preconnect jwapp.com

* fix: broken checkbox in personal details form

* fix: hide disabled questions in personal details screen

* fix: improve consents required form error

* fix: show error when delete account fails

* fix: hide optional label in season select dropdown

* fix: shelf margin and grid loading state

* chore: add default config and set demo mode on for build (#127)

* feat: Render favicons dynamically

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* refactor(payment): improve choose offer flow

* fix(payment): ui not updating after paypal payment

* refactor: add strict util for modal urls from window location

* feat(a11y): add auto focus to play/pause button of players

* fix(menu): prevent text to go on two lines in buttons

* fix(a11y): ensure wcag compliance with 1.5 line-height for texts (#109)

* feat(a11y): apply the autocomplete attribute to input fields(#115)

* feat(a11y): apply correct aria attributes and improve searchbar (#117)

* feat(a11y): video meta data items separated (#116)

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix(a11y): only set focus programmatically on keyboard navigation

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* feat(a11y): form validation improvements for screen readers

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix(a11y): apply aria-hidden to checkbox asterisk (#121)

* feat(a11y): slide chevron buttons hitarea increased

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix(a11y): usermenu item count & correct html structure

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix(a11y): roles and aria-attributes regarding modals (#125)

* feat(a11y): slider navigation optimized

* chore: fix react warning

* fix(payment): layout of invoices on mobile

* fix(a11y): optimize footer for accessibility

* feat(a11y): improve accessibility of sidebar

* feat(a11y): optimize profile menu

* fix(a11y): improve screenreader focus on start watching button

* fix(a11y): videoplayer focus (iOS) & restoration

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix: active state of language menu and apply aria-current

* fix(search): prevent keyboard from persisting in searchbar on submit

* fix(a11y): ensure correct focus on first sidebar menu item

* fix(user): update question value while typing

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix(videodetail): don’t render empty duration metadata

* fix(user): error when updating customer

* fix(project): checkbox values for customer consents

* fix(menu): ensure sidebar is scrollable

* refactor(menu): apply dynamic viewport height for sidebar

* fix(project): overall styling of the hub page

* fix(payment): fix new subscription not showing in UI

* fix: cinema not covering full viewport height

* fix(videodetail): page behind player too wide

* fix(videodetail): buttons not aligning properly

* feat: align sidebar backdrop with modal

* fix(a11y): add selected state to season filters

* fix(a11y): add role to make lock icon readable

refactor(tests): update snapshots

* fix(a11y): add aria-pressed to password icon and underline to footer links

* fix: video metadata styling with status icon for live events

* chore: format package files

* fix(player): back button not working

* fix(player): title overlay fade animation

* chore(project): maintenance 2024-q1

* chore: enable verbatimModuleSyntax

* chore: use cjs for lighthouse config

* chore: add comment to s3 workflow

* refactor: extract metadata utils

* chore: cleanup translations

---------

Co-authored-by: Vincent Couzij <vincent@videodock.com>
Co-authored-by: Melissa Hart <48496458+MelissaDTH@users.noreply.github.com>
Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>
Co-authored-by: langemike <mikevv@gmail.com>
Co-authored-by: Roy Schut <roy@videodock.com>
Co-authored-by: Roy Schut <royschut@gmail.com>
Co-authored-by: Melissa 't Hart <melissa@videodock.com>
This was referenced Mar 21, 2024
AntonLantukh added a commit that referenced this issue Mar 27, 2024
* feat(project)!: restructure for multiplatforms with workspaces (#435)

* refactor: initialize workspace and separate services, stores and utils

* chore: update configurations and set up linting

* refactor(project): move web assets to theme package

refactor(project): move poster aspect to constants

refactor(project): move test fixtures and utils

refactor: move hooks to react-hooks package

chore: configurations and testing

refactor: add mockService helper

chore: remove .only from useLiveChannels test

refactor: move components, containers and pages to ui-react package

refactor: rename @jwplayer org to @jwp

chore: fix epg fixtures for testing

chore: fix unmet peer dependency warnings

chore: fix e2e typings

* docs: add i18n package readme

chore(i18n): update i18next scripts

* refactor: store supported languages in config store

* chore: update release workflow

* refactor: move web into platforms directory

* chore: update web platform directory in workflows

* chore: update gitignore

* chore: fix epg fixtures

* refactor(project): remove vite from common, ui-react and hooks-react (#8)

* refactor: replace meta env imports with common env object

* refactor(tests): fix broken ui-react unit tests

* refactor(project): add scss typings

* refactor(project): remove obsolete ts rule

* refactor(tests): make sure mode and dev are globally available

* refactor(project): minor code upgrade

Co-authored-by: Christiaan Scheermeijer <christiaan@videodock.com>

---------

Co-authored-by: Christiaan Scheermeijer <christiaan@videodock.com>

* feat: remove browser typings from common

* refactor(project): remove react from common package (#9)

* refactor: replace meta env imports with common env object

* refactor(tests): fix broken ui-react unit tests

* refactor(project): add scss typings

* refactor(project): remove obsolete ts rule

* refactor(tests): make sure mode and dev are globally available

* refactor(project): remove react and react-router-dom from common

* refactor(project): replace react-query with tanstack/query-core in common

* refactor(project): add location.search string failsafe

* feat(player): show nice error message when media item is geo blocked

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* refactor(project): move icons to theme folder (#21)

* refactor(project): add createURL util to replace all url utils

* refactor(project): remove react-router from hooks-react package

* refactor: allow custom integration registration via container

chore: fix scss module import autocomplete in IDE

chore: cleanup

chore: rename calculate_intergration_type

fix: jwp account service injection

chore: fix unit tests

refactor: move get integration type check

# Conflicts:
#	packages/common/src/services/integrations/cleeng/CleengSubscriptionService.ts
#	packages/ui-react/src/containers/AdyenPaymentDetails/AdyenPaymentDetails.tsx
#	packages/ui-react/src/pages/Home/__snapshots__/Home.test.tsx.snap

* refactor(project): split url creation from location based

* feat(accessibility): accessibility improvements and quick wins

* feat(a11y): correct heading structure

* refactor(a11y): modal id and a11y style selector

* refactor(home): add home scss file

* chore(a11y): add hidden h1 element to payment page

* refactor(project): move accessibility import to main scss file

* refactor(e2e): update tests after changes to header hierarchy

* refactor(project): update styling import

* refactor(tests): update account snapshot

* feat(a11y): correct heading structure

* refactor(a11y): modal id and a11y style selector

* feat(a11y): add skiplink to header and update translations

* refactor(project): add tabIndex prop and update translations

* refactor(project): update import and move styling variable

* refactor(project): add hidden h1 element to correct eelements

* refactor(a11y): move hidden header element in dom structure

* feat(a11y): link underlines, role attribute and page titles

* feat(a11y): add an underline to links at all times

* feat(a11y): add role attribute to dialogs

* feat(a11y): add role attribute to dialogs

* chore(a11y): apply aria-labelledby

* chore(a11y): useOpaqueId for id

* chore(a11y): improve role attribute value for test

* chore: fix merge mistake

---------

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

---------

Co-authored-by: Roy Schut <roy@videodock.com>
Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix(a11y): alertdialog with aria-modal for alert component

* fix(a11y): role=“alertdialog” for alert component with id fix

* fix(a11y): add aria-modal to alert component

---------

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix(a11y): apply section to account and payment pages

* fix(a11y): add prop arialabeledby to account sections

* fix(tests): update useOpaqueId and snapshots

* fix(a11y): update paymnents page sections with the correct prop

---------

Co-authored-by: Rachid <rachid.ang@sounds.global>
# Conflicts:
#	packages/ui-react/src/components/Payment/Payment.tsx

* refactor(a11y): refactor language menu switch for accessibility compliance

* fix(a11y): cards optimized for screen readers

* fix(a11y): card optimized for screen readers

* chore: update snapshots

* chore: rewrite unit tests for image with empty alt

* fix(e2e): rewrite aria-label with data-label for testing purposes

---------

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>
# Conflicts:
#	packages/ui-react/src/components/Card/Card.tsx
#	packages/ui-react/src/pages/Home/__snapshots__/Home.test.tsx.snap

* feat(i18n): reflect language switching in root html lang tag.

Co-authored-by: Rachid <rachid.ang@sounds.global>

* feat(a11y): make user menu keyboard accessible

* fix: language menu button

* fix: slow login and preventable errors

* fix: load subscription after restoring SVOD session

* fix(auth): set the correct loading state after logging the user in account-controller

* fix: refresh entitlements on tvod purchase

* chore: fix depcheck errors

* fix: infinite loader when buying a subscription

* docs(project): update documentation for workspaces

* chore: rename web specific workflows

* chore: pr feedback

* chore: move build packages to configs directory

* fix: epg service bindings

---------

Co-authored-by: Roy Schut <royschut@gmail.com>
Co-authored-by: langemike <mikevv@gmail.com>
Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>
Co-authored-by: Melissa Hart <48496458+MelissaDTH@users.noreply.github.com>
Co-authored-by: Roy Schut <roy@videodock.com>
Co-authored-by: Rachid Angelista <80318554+R-Cloud-Designs@users.noreply.github.com>
Co-authored-by: Rachid <rachid.ang@sounds.global>

* feat(project): dynamic gtm snippet

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* refactor(project): make route definitions static and improve url utils

* refactor: refactor typings

* fix(auth): capture error to prevent misleading “wrong combination” error

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* feat(project): customizable footer through env-var

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* refactor(project): add replaceable components to ui-react

* feat(project): favicons in different sizes

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* chore(project): dynamic manifest.json

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* chore: update depcheck

* fix(player): inlineplayer not supporting tvod

* fix(user): tvod subscription not reloaded after login for authvod/avod

* refactor(payment): fix hasTVODOffers not properly defined

* docs(project): update url signing link

* fix(payment): subscription offer panel shown for authvod+tvod

* refactor(payment): simplify useOffers hook

* refactor(user): prevent unnecessary subscription calls

* refactor(user): let reloadSubscriptions handle all access modals

* refactor: Cleeng and Inplayer account typings

* fix(project): show footer when custom footer is provided

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix/checkout bugs

* fix(account): delete account error

* refactor: move controllers and refactor form logic

* fix: favorites and history validation error

* fix(payment): redirect after incorrect couponcode entry

* fix(payment): tvod offer not showing in AuthVOD platform

* fix(payment): incorrect couponCode success message

* fix: root error screen for unexpected errors

* fix(project): undouble serieIds to prevent crash

* fix: hide start watching button in avod platform

* fix: e2e test optimisations and small fixes

* refactor: revisit login and register try catch flow

* refactor: move form validation error and pass all errors

* refactor: add loading state for publisher consents

* fix: set wrong loading state in early return

* fix: update order error handling

* refactor: simplify path constants

* refactor: use keyed object in submit paypal method

* chore: revert config footer text removal

* refactor: render error to component

* fix: restore personal shelves after registration

* fix: personal shelves restoration

* feat(a11y): many accessibility optimisations

fix(a11y): prevent double ids on inputs by requiring a name

feat(a11y): apply aria-modal attribute and move header landmark (#48)

feat(a11y): update button role and html structure of account and player pages (#47)

feat(a11y): add correct text markups and aria attributes (#46)

feat(home): add (geo) error message when all playlists are empty

feat(a11y): add form error announcement

feat(a11y): add solid header background color to ensure accessibility

feat(a11y): implement aria-invalid and aria-described by to inputs on error

feat(project): add google fonts from env vars

feat: keyboard accessible LayoutGrid

feat: optimize featured shelf slider for accessibility

feat(a11y): accessible sidebar & <main> landmark

feat(a11y): enhance dialog and modals accessibility

fix(a11y): alt text for images for EPG

fix(a11y): empty alt for image because of adjacent text alternative

fix(a11y): fix arrow keys for offer radio buttons

fix(a11y): skiplink first element

feat(a11y): improve html structure for VideoListItem

fix(e2e): cardgrid card navigation

feat(a11y): apply lang attribute to custom fields

feat(a11y): accessible focus outline

* fix(project): create missing pwa icons

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* feat(a11y): update font colors for contrast and adjust active state in header (#76)

* fix(a11y): prevent duplicate global a11y selectors

* fix(a11y): shelf item navigation with screen reader

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* chore: update snapshots

* fix: language menu icon not centered

* fix(a11y): remove outline when user is not tabbing

* fix(a11y): format date call caused an error to be raised

* fix(menu): ensure logo does not exceed width of the header

* refactor(a11y): remove double account header and add translations

* fix(a11y): constrast enhancement for search field

* feat: underline for active header item and add lineair gradient

* fix: enter key not closing the account modal

* fix: logo and header layout issues

* fix(a11y): close search bar when pressing escape

* fix: e2e tests for a11y

* fix: related videos title layout issue

* fix: footer overlap fix

* fix: click not working in layout grid

* refactor: remove reactive focus from layout grid

* fix: layout grid home and page down problem

* fix: layout grid arrow down and end problem

* fix(project): fix live stream duration check for ott plugin (#460)

* feat: accessibility improvements and bug fixes

* chore: add pr deployment previews workflows

* fix(payment): redirect to wrong media after payment

* chore: add version number to footer text

Co-authored-by: Melissa Hart <48496458+MelissaDTH@users.noreply.github.com>

* fix: show error on email field when invalid

* fix(project): favicons & preconnect jwapp.com

* fix: broken checkbox in personal details form

* fix: hide disabled questions in personal details screen

* fix: improve consents required form error

* fix: show error when delete account fails

* fix: hide optional label in season select dropdown

* fix: shelf margin and grid loading state

* chore: add default config and set demo mode on for build (#127)

* feat: Render favicons dynamically

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* refactor(payment): improve choose offer flow

* fix(payment): ui not updating after paypal payment

* refactor: add strict util for modal urls from window location

* feat(a11y): add auto focus to play/pause button of players

* fix(menu): prevent text to go on two lines in buttons

* fix(a11y): ensure wcag compliance with 1.5 line-height for texts (#109)

* feat(a11y): apply the autocomplete attribute to input fields(#115)

* feat(a11y): apply correct aria attributes and improve searchbar (#117)

* feat(a11y): video meta data items separated (#116)

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix(a11y): only set focus programmatically on keyboard navigation

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* feat(a11y): form validation improvements for screen readers

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix(a11y): apply aria-hidden to checkbox asterisk (#121)

* feat(a11y): slide chevron buttons hitarea increased

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix(a11y): usermenu item count & correct html structure

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix(a11y): roles and aria-attributes regarding modals (#125)

* feat(a11y): slider navigation optimized

* chore: fix react warning

* fix(payment): layout of invoices on mobile

* fix(a11y): optimize footer for accessibility

* feat(a11y): improve accessibility of sidebar

* feat(a11y): optimize profile menu

* fix(a11y): improve screenreader focus on start watching button

* fix(a11y): videoplayer focus (iOS) & restoration

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix: active state of language menu and apply aria-current

* fix(search): prevent keyboard from persisting in searchbar on submit

* fix(a11y): ensure correct focus on first sidebar menu item

* fix(user): update question value while typing

Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>

* fix(videodetail): don’t render empty duration metadata

* fix(user): error when updating customer

* fix(project): checkbox values for customer consents

* fix(menu): ensure sidebar is scrollable

* refactor(menu): apply dynamic viewport height for sidebar

* fix(project): overall styling of the hub page

* fix(payment): fix new subscription not showing in UI

* fix: cinema not covering full viewport height

* fix(videodetail): page behind player too wide

* fix(videodetail): buttons not aligning properly

* feat: align sidebar backdrop with modal

* fix(a11y): add selected state to season filters

* fix(a11y): add role to make lock icon readable

refactor(tests): update snapshots

* fix(a11y): add aria-pressed to password icon and underline to footer links

* fix: video metadata styling with status icon for live events

* chore: format package files

* fix(player): back button not working

* fix(player): title overlay fade animation

* chore(project): maintenance 2024-q1

* chore: enable verbatimModuleSyntax

* chore: use cjs for lighthouse config

* chore: add comment to s3 workflow

* refactor: extract metadata utils

* chore: cleanup translations

---------

Co-authored-by: Vincent Couzij <vincent@videodock.com>
Co-authored-by: Melissa Hart <48496458+MelissaDTH@users.noreply.github.com>
Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>
Co-authored-by: langemike <mikevv@gmail.com>
Co-authored-by: Roy Schut <roy@videodock.com>
Co-authored-by: Roy Schut <royschut@gmail.com>
Co-authored-by: Melissa 't Hart <melissa@videodock.com>

* feat(watchhistory): change max items limit (#418)

* feat(watchhistory): change max items limit

* feat(payment): disable deprecated receipts cleeng (#458)

* chore: replace depcheck with knip (#462)

* chore: replace depcheck with knip

* chore: run prettier on knip.config.ts

* chore: revert to knip entry instead of package exports

* chore: fix prettier

* docs(project): update docs for workspaces

* docs: spellcheck and fix feedback

* feat(project): update default content-type schemas

* fix(project): unused dep

* fix(project): ensure modals obscure underlying elements

* feat(project): add app content search

* chore(release): v6.0.0

* feat(project): update translations

* fix(project): fix es translations

---------

Co-authored-by: Christiaan Scheermeijer <christiaan@videodock.com>
Co-authored-by: Roy Schut <royschut@gmail.com>
Co-authored-by: langemike <mikevv@gmail.com>
Co-authored-by: Mike van Veenhuijzen <mike@videodock.com>
Co-authored-by: Melissa Hart <48496458+MelissaDTH@users.noreply.github.com>
Co-authored-by: Roy Schut <roy@videodock.com>
Co-authored-by: Rachid Angelista <80318554+R-Cloud-Designs@users.noreply.github.com>
Co-authored-by: Rachid <rachid.ang@sounds.global>
Co-authored-by: Anton Lantukh <alantukh@jwplayer.com>
Co-authored-by: Melissa 't Hart <melissa@videodock.com>
Co-authored-by: Vincent Couzij <vincent@videodock.com>
Co-authored-by: Conventional Changelog Action <conventional.changelog.action@github.com>
@ChristiaanScheermeijer
Copy link
Collaborator

@dbudzins @AntonLantukh @royschut @langemike @MelissaDTH

In the next sprint, we will implement a logging application, and I think this might help with that.

We've used Pino before, but this is mainly created for NodeJS applications and might be overkill.

Now that we have services, I am considering creating a LoggingService with a simple interface. For example:

interface ILoggingService {
  debug(namespace: string, ...args: unknown[]): void;
  info(namespace: string, ...args: unknown[]): void;
  warn(namespace: string, ...args: unknown[]): void;
  error(namespace: string, error: Error, ...args: unknown[]): void;
  fatal(namespace: string, error: Error, ...args: unknown[]): void;
  
  // optionally implement support for (custom) transporters, for example:
  // consoleTransporter, sentryTransporter, cloudWatchTransporter, ... 
  registerTransporter(transporter: (level: string, args: unknown[], error?: Error) => void): void;
}

I see two potential ways of adding a logging implementation.

Allow for registering custom transporters (see above)

  • Pro: This allows for multiple transporters (easier)
  • Pro: Less logic to re-implement (determine the log level and which logs to output)
  • Con: More logic to implement initially

Override the default LoggingService with a custom implementation

  • Pro: Full control
  • Pro: Easier to maintain and implement
  • Con: Custom implementations need to implement more

Although, a third solution is to override the existing LoggingService and only override a generic method that handles the actual logging. This might be even more simple:

class SentryLoggingService extends LoggingService {
  override log(level: string, namespace: string, args: unknown[], error?: Error) {
    // console logging
    super.log(level, namespace, args, error);

    // log to Sentry
    Sentry.captureMessage(`[${namespace}]: ${args.join(',')}`, level);
  }
}

Should we accept only one string and mark the rest as additional data (context) which may be useful debug data?

interface ILoggingService {
  debug(namespace: string, message: string, ...additionalData: unknown[]): void;
  // ...
}

What do you think?

@dbudzins
Copy link
Contributor Author

I think the first option (a single service with configurable transports) is the cleanest. I'm not sure how it's more work initially, maybe it's just being careful about separation of concerns? Options 2 or 3 are then always available to anyone else who needs anything more complex.

@AntonLantukh
Copy link
Collaborator

We could probably stick to the approach we already have with Account / Checkout services:

  1. Create LoggingService which is "abstract class" and required methods like "registerTransporter" and "log".
  2. Create basic implementation.
  3. When needed basic implementation can be replaced with a custom one.

This one looks like both first and second option?

@ChristiaanScheermeijer
Copy link
Collaborator

ChristiaanScheermeijer commented May 27, 2024

@dbudzins @AntonLantukh, thanks for the feedback!

I don't think it's needed for a mechanism like integrations because it's just one service instead of multiple services for one integration. We also don't apply this for the EntitlementService (yet).

If we go for option 1, I think the default console transporter should also be registered like custom transporters. The question is, where do we create and register this transporter?

In register.ts

// Logging
container.bind(LoggingService).toSelf();
container.get(LoggingService).registerTransporter(consoleTransporter);

We can also leverage the container with multiple services. This is an alternative solution to the registerTransporter method.

// Logging
container.bind(LogginService).toSelf();
container.bind(LOG_TRANSPORTER_TYPE).to(ConsoleTransporter);
container.bind(LOG_TRANSPORTER_TYPE).to(AnalyticsTransporter);
container.bind(LOG_TRANSPORTER_TYPE).to(SentryTransporter);

The LoggingService will just call the log method on all transporters and can be easily extended with more (custom) log transporters:

class LoggingService {
  log(...args) {
    container.getAll(LOG_TRANSPORTER_TYPE).map(transporter => transporter.log(...args));
  }
}

@dbudzins
Copy link
Contributor Author

Console default makes sense for dev and test, but not prod or demo. Support for multiples is nice.

I'm assuming most transporters will need some configuration, too right? My first thought is to put these settings into the ini file because they are mostly set-and-forget.

@ChristiaanScheermeijer
Copy link
Collaborator

Yes, it would make sense to have some configuration available per transporter. I would also like to configure the log level per transporter as well.

Ini files may sound great, but the downside is that logging is only initialized when the ini file is loaded. This is too late to capture errors with Sentry (for example, when a JS or the ini file fails to load).

I don't have an alternative solution (yet) though...

@ChristiaanScheermeijer
Copy link
Collaborator

These are the current options:

  1. Using an environment variable (works only when running build). For example: APP_LOGGING=console:info,sentry:error,gtm:off
  2. Configure the log settings in the index.html using a script tag
  3. Configure the log settings in the ini settings file
  4. Configure the log settings in the app config (not preferred)

Do you see alternatives?

@ChristiaanScheermeijer
Copy link
Collaborator

I have drafted a quick proposal. This does require editing the source to modify the logging behavior, but I assume this will be the case anyways when adding custom logging frameworks. I think the repo should only provide the ConsoleTransporter configured to log everything when running in dev mode.

Let me know what you think.

enum LogLevel {
  DEBUG,
  INFO,
  WARN,
  ERROR,
  FATAL,
  SILENT,
}

interface LoggingTransporter {
  logLevel: LogLevel;
  log(level: LogLevel, scope: string, message: string, extra?: Record<string, unknown>, error?: Error): void;
}

const LOG_TRANSPORTER_TYPE = Symbol('LOG_TRANSPORTER_TYPE');

class LoggingService {
  private log(logLevel: LogLevel, scope: string, message: string, extra?: Record<string, unknown>, error?: Error) {
    container.getAll<LoggingTransporter>(LOG_TRANSPORTER_TYPE).forEach((transporter) => {
      // preventing the call here does limit options like adding breadcrumbs (which might be inferred from info logs) to Sentry calls
      if (logLevel >= transporter.logLevel) {
        transporter.log(logLevel, scope, message, extra, error);
      }
    });
  }

  debug = (scope: string, message: string, extra?: Record<string, unknown>) => this.log(LogLevel.DEBUG, scope, message, extra);
  info = (scope: string, message: string, extra?: Record<string, unknown>) => this.log(LogLevel.INFO, scope, message, extra);
  warn = (scope: string, message: string, extra?: Record<string, unknown>) => this.log(LogLevel.WARN, scope, message, extra);
  error = (scope: string, message: string, error: Error, extra?: Record<string, unknown>) => this.log(LogLevel.ERROR, scope, message, extra, error);
  fatal = (scope: string, message: string, error: Error, extra?: Record<string, unknown>) => this.log(LogLevel.FATAL, scope, message, extra, error);
}

class ConsoleTransporter implements LoggingTransporter {
  logLevel: LogLevel;

  constructor({ logLevel }: { logLevel: LogLevel }) {
    this.logLevel = logLevel;
  }

  log(level: LogLevel, scope: string, message: string, extra?: Record<string, unknown> | undefined, error?: Error | undefined): void {
    if (this.logLevel === LogLevel.SILENT) return;

    console.info(`[${level}] ${scope}: ${message}`);

    if (level === LogLevel.ERROR || level === LogLevel.FATAL) {
      console.error(error);
    }

    if (extra) {
      // eslint-disable-next-line no-console
      console.table(extra);
    }
  }
}

// Configure the generic LoggingService in the common package
container.bind(LoggingService).toSelf();

// Configure the transporter in web/src/modules/register.ts
container.bind<LoggingTransporter>(LOG_TRANSPORTER_TYPE).toDynamicValue(
  () =>
    new ConsoleTransporter({
      logLevel: import.meta.env.DEV ? LogLevel.DEBUG : LogLevel.SILENT,
    }),
);

// This is a custom transporter added by the publisher
container.bind<LoggingTransporter>(LOG_TRANSPORTER_TYPE).toDynamicValue(
  () =>
    new SentryTransporter({
      logLevel: import.meta.env.DEV ? LogLevel.SILENT : LogLevel.ERROR, // log ERROR and FATAL to Sentry on production
      includeBreadcrumbs: true, // include breadcrumbs example configuration
    }),
);

@ChristiaanScheermeijer
Copy link
Collaborator

I think we can rename everything to LogService and LogTransporter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants