googleapis / nodejs-logging

Node.js client for Stackdriver Logging: Store, search, analyze, monitor, and alert on log data and events from Google Cloud Platform and Amazon Web Services (AWS).
https://cloud.google.com/logging/
Apache License 2.0
172 stars 62 forks source link

feat: Simple Synchronous Logger w/ Error Reporting Support #1407

Open danielbankhead opened 1 year ago

danielbankhead commented 1 year ago

It would be cool if this library included a simple, ready-to-go synchronous logger that:

I often reuse a class like this between projects: https://github.com/danielbankhead/picture-playlist/blob/main/src/lib/logger.ts

/**
 * Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {Logging, SeverityNames, Entry} from '@google-cloud/logging';

import {config} from './config.js';
import {packageJson} from './utils/package.js';

const logging = new Logging();
await logging.setProjectId();
await logging.setDetectedResource();

const log = logging.logSync(packageJson.name);

enum LoggingTypes {
  /**
   * @link https://cloud.google.com/error-reporting/docs/formatting-error-messages
   */
  ReportedErrorEvent = 'type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent',
}

type Meta = Entry['metadata'];
type Data = Entry['data'];

type SeverityFunctions = {
  [_ in SeverityNames]: (message: unknown, data?: Data, meta?: Meta) => void;
};

class Logger implements SeverityFunctions {
  /**
   * Internal method for logging for each severity
   */
  #log(s: SeverityNames, message: unknown, data?: Data, meta?: Meta) {
    const payload: {message: unknown; data?: Data; '@type'?: string} = {
      message,
      data,
    };

    if (message instanceof Error && message.stack) {
      // Allows error to be pick up by Error Reporting
      // https://cloud.google.com/error-reporting/docs/formatting-error-messages
      payload.message = message.stack;
      payload['@type'] = LoggingTypes.ReportedErrorEvent;
    }

    const entry = log.entry(meta, payload);

    log[s](entry);
  }

  info(message: unknown, data?: Data, meta?: Meta) {
    return this.#log('info', message, data, meta);
  }

  emergency(message: unknown, data?: Data, meta?: Meta) {
    return this.#log('emergency', message, data, meta);
  }

  alert(message: unknown, data?: Data, meta?: Meta) {
    return this.#log('alert', message, data, meta);
  }

  critical(message: unknown, data?: Data, meta?: Meta) {
    return this.#log('critical', message, data, meta);
  }

  error(message: unknown, data?: Data, meta?: Meta) {
    return this.#log('error', message, data, meta);
  }

  warning(message: unknown, data?: Data, meta?: Meta) {
    return this.#log('warning', message, data, meta);
  }

  notice(message: unknown, data?: Data, meta?: Meta) {
    return this.#log('notice', message, data, meta);
  }

  debug(message: unknown, data?: Data, meta?: Meta) {
    if (config.logging.verbose) {
      this.#log('debug', message, data, meta);
    }
  }
}

export const logger = new Logger();

Let me know if you have any questions or need help integrating!