本格的なアプリを作成する場合は Sentry などのサービスを使うことが多いと思います。

そこまでは必要ないけれど、エラーログの仕組みをマニュアルで簡易的に作成してきたい時の作り方。

function throwError() {
  throw new Error('Sorry, (;-;) something happened.');
}

function throwErrorInPromise() {
  return new Promise(() => {
    throw new Error('Sorry, (;-;) something happened in promise.');
  });
}

function log(e) {
  console.error(e); // 実際にはデータベースにログを記録したりとか
}

1. 個別に捕捉したエラーを記録する

try…catch や Promise の catch で捕捉したエラーをロギングするときはこんな感じです。

// 通常の関数(同期関数)の場合

try {
  throwError();
} catch (e) {
  log(e);
}

// 非同期関数の場合(書き方いろいろ)

try {
  await throwErrorInPromise();
} catch (e) {
  log(e);
}

throwErrorInPromise().catch(log);

(async () => {
  await throwErrorInPromise();
})().catch(log);

2. Window イベントを捕捉する

try…catch 等の個別の補足から漏れてしまったものはこちらで捕まえます。

window.addEventListener('error', (event) => {
  log(event.message);
});

window.addEventListener('unhandledrejection', (event) => {
  log(event.reason);
});

throwError(); // 'error' で捕捉される

throwErrorInPromise(); // 'unhandledrejection' で捕捉される

通常のエラーは Window: error イベントとなり、Promise でのエラーは Window: unhandledrejection イベントとなるため、両方を設定しておく必要があります。

FYI: