From fb98977b172f8f4458f8d14905d0a08356307f64 Mon Sep 17 00:00:00 2001
From: Daniel Dyla <dyladan@users.noreply.github.com>
Date: Thu, 25 Feb 2021 15:49:49 -0500
Subject: [PATCH] chore: refactor diag logger (#9)

---
 .eslintrc.js                        |   1 +
 package.json                        |   2 +-
 src/api/diag.ts                     | 114 ++++++++++++-------------
 src/diag/consoleLogger.ts           |   2 +-
 src/diag/index.ts                   |  18 ++++
 src/diag/internal/logLevelLogger.ts |  51 +++++++++++
 src/diag/internal/noopLogger.ts     |  34 ++++++++
 src/diag/logLevel.ts                | 126 ----------------------------
 src/diag/{logger.ts => types.ts}    |  45 +++++-----
 src/index.ts                        |   8 +-
 test/api/api.test.ts                |  11 ++-
 test/diag/consoleLogger.test.ts     |   9 +-
 test/diag/logLevel.test.ts          |  92 ++++----------------
 test/diag/logger.test.ts            |  42 ++++++++--
 tsconfig.docs.json                  |  15 ----
 15 files changed, 256 insertions(+), 314 deletions(-)
 create mode 100644 src/diag/index.ts
 create mode 100644 src/diag/internal/logLevelLogger.ts
 create mode 100644 src/diag/internal/noopLogger.ts
 delete mode 100644 src/diag/logLevel.ts
 rename src/diag/{logger.ts => types.ts} (74%)
 delete mode 100644 tsconfig.docs.json

diff --git a/.eslintrc.js b/.eslintrc.js
index 507822e8..e1e62430 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -32,6 +32,7 @@ module.exports = {
         "@typescript-eslint/no-inferrable-types": ["error", { ignoreProperties: true }],
         "arrow-parens": ["error", "as-needed"],
         "prettier/prettier": ["error", { "singleQuote": true, "arrowParens": "avoid" }],
+        "prefer-spread": "off",
         "node/no-deprecated-api": ["warn"],
         "header/header": [2, "block", [{
             pattern: / \* Copyright The OpenTelemetry Authors[\r\n]+ \*[\r\n]+ \* Licensed under the Apache License, Version 2\.0 \(the \"License\"\);[\r\n]+ \* you may not use this file except in compliance with the License\.[\r\n]+ \* You may obtain a copy of the License at[\r\n]+ \*[\r\n]+ \*      https:\/\/www\.apache\.org\/licenses\/LICENSE-2\.0[\r\n]+ \*[\r\n]+ \* Unless required by applicable law or agreed to in writing, software[\r\n]+ \* distributed under the License is distributed on an \"AS IS\" BASIS,[\r\n]+ \* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\.[\r\n]+ \* See the License for the specific language governing permissions and[\r\n]+ \* limitations under the License\./gm,
diff --git a/package.json b/package.json
index 4bd6ac87..d0e1500a 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,7 @@
     "codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p .",
     "compile": "tsc --build",
     "docs-test": "linkinator docs/out --silent --skip david-dm.org",
-    "docs": "typedoc --tsconfig tsconfig.docs.json",
+    "docs": "typedoc",
     "lint:fix": "eslint src test --ext .ts --fix",
     "lint": "eslint src test --ext .ts",
     "test:browser": "nyc karma start --single-run",
diff --git a/src/api/diag.ts b/src/api/diag.ts
index 58a5cdd1..b32b6b25 100644
--- a/src/api/diag.ts
+++ b/src/api/diag.ts
@@ -14,13 +14,9 @@
  * limitations under the License.
  */
 
-import {
-  DiagLogger,
-  DiagLogFunction,
-  createNoopDiagLogger,
-  diagLoggerFunctions,
-} from '../diag/logger';
-import { DiagLogLevel, createLogLevelDiagLogger } from '../diag/logLevel';
+import { createLogLevelDiagLogger } from '../diag/internal/logLevelLogger';
+import { createNoopDiagLogger } from '../diag/internal/noopLogger';
+import { DiagLogFunction, DiagLogger, DiagLogLevel } from '../diag/types';
 import {
   API_BACKWARDS_COMPATIBILITY_VERSION,
   GLOBAL_DIAG_LOGGER_API_KEY,
@@ -28,15 +24,14 @@ import {
   _global,
 } from './global-utils';
 
+function nop() {}
+
 /** Internal simple Noop Diag API that returns a noop logger and does not allow any changes */
 function noopDiagApi(): DiagAPI {
-  const noopApi = createNoopDiagLogger() as DiagAPI;
-
-  noopApi.getLogger = () => noopApi;
-  noopApi.setLogger = noopApi.getLogger;
-  noopApi.setLogLevel = () => {};
-
-  return noopApi;
+  return Object.assign(
+    { disable: nop, setLogger: nop },
+    createNoopDiagLogger()
+  );
 }
 
 /**
@@ -71,21 +66,18 @@ export class DiagAPI implements DiagLogger {
    * @private
    */
   private constructor() {
-    let _logLevel: DiagLogLevel = DiagLogLevel.INFO;
-    let _filteredLogger: DiagLogger | null;
-    let _logger: DiagLogger = createNoopDiagLogger();
+    let _filteredLogger: DiagLogger | undefined;
 
     function _logProxy(funcName: keyof DiagLogger): DiagLogFunction {
       return function () {
-        const orgArguments = arguments as unknown;
-        const theLogger = _filteredLogger || _logger;
-        const theFunc = theLogger[funcName];
-        if (typeof theFunc === 'function') {
-          return theFunc.apply(
-            theLogger,
-            orgArguments as Parameters<DiagLogFunction>
-          );
-        }
+        // shortcut if logger not set
+        if (!_filteredLogger) return;
+        return _filteredLogger[funcName].apply(
+          _filteredLogger,
+          // work around Function.prototype.apply types
+          // eslint-disable-next-line @typescript-eslint/no-explicit-any
+          arguments as any
+        );
       };
     }
 
@@ -94,52 +86,47 @@ export class DiagAPI implements DiagLogger {
 
     // DiagAPI specific functions
 
-    self.getLogger = (): DiagLogger => {
-      // Return itself if no existing logger is defined (defaults effectively to a Noop)
-      return _logger;
-    };
-
-    self.setLogger = (logger?: DiagLogger): DiagLogger => {
-      const prevLogger = _logger;
-      if (!logger || logger !== self) {
-        // Simple special case to avoid any possible infinite recursion on the logging functions
-        _logger = logger || createNoopDiagLogger();
-        _filteredLogger = createLogLevelDiagLogger(_logLevel, _logger);
+    self.setLogger = (
+      logger: DiagLogger,
+      logLevel: DiagLogLevel = DiagLogLevel.INFO
+    ) => {
+      if (logger === self) {
+        if (_filteredLogger) {
+          const err = new Error(
+            'Cannot use diag as the logger for itself. Please use a DiagLogger implementation like ConsoleDiagLogger or a custom implementation'
+          );
+          _filteredLogger.error(err.stack ?? err.message);
+          logger = _filteredLogger;
+        } else {
+          // There isn't much we can do here.
+          // Logging to the console might break the user application.
+          return;
+        }
       }
 
-      return prevLogger;
+      _filteredLogger = createLogLevelDiagLogger(logLevel, logger);
     };
 
-    self.setLogLevel = (maxLogLevel: DiagLogLevel) => {
-      if (maxLogLevel !== _logLevel) {
-        _logLevel = maxLogLevel;
-        if (_logger) {
-          _filteredLogger = createLogLevelDiagLogger(maxLogLevel, _logger);
-        }
-      }
+    self.disable = () => {
+      _filteredLogger = undefined;
     };
 
-    for (let i = 0; i < diagLoggerFunctions.length; i++) {
-      const name = diagLoggerFunctions[i];
-      self[name] = _logProxy(name);
-    }
+    self.verbose = _logProxy('verbose');
+    self.debug = _logProxy('debug');
+    self.info = _logProxy('info');
+    self.warn = _logProxy('warn');
+    self.error = _logProxy('error');
   }
 
   /**
-   * Return the currently configured logger instance, if no logger has been configured
-   * it will return itself so any log level filtering will still be applied in this case.
-   */
-  public getLogger!: () => DiagLogger;
-
-  /**
-   * Set the DiagLogger instance
-   * @param logger - [Optional] The DiagLogger instance to set as the default logger, if not provided it will set it back as a noop
+   * Set the global DiagLogger and DiagLogLevel.
+   * If a global diag logger is already set, this will override it.
+   *
+   * @param logger - [Optional] The DiagLogger instance to set as the default logger.
+   * @param logLevel - [Optional] The DiagLogLevel used to filter logs sent to the logger. If not provided it will default to INFO.
    * @returns The previously registered DiagLogger
    */
-  public setLogger!: (logger?: DiagLogger) => DiagLogger;
-
-  /** Set the default maximum diagnostic logging level */
-  public setLogLevel!: (maxLogLevel: DiagLogLevel) => void;
+  public setLogger!: (logger: DiagLogger, logLevel?: DiagLogLevel) => void;
 
   // DiagLogger implementation
   public verbose!: DiagLogFunction;
@@ -147,4 +134,9 @@ export class DiagAPI implements DiagLogger {
   public info!: DiagLogFunction;
   public warn!: DiagLogFunction;
   public error!: DiagLogFunction;
+
+  /**
+   * Unregister the global logger and return to Noop
+   */
+  public disable!: () => void;
 }
diff --git a/src/diag/consoleLogger.ts b/src/diag/consoleLogger.ts
index 7ea2e9cd..8e18e0fa 100644
--- a/src/diag/consoleLogger.ts
+++ b/src/diag/consoleLogger.ts
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import { DiagLogger, DiagLogFunction } from './logger';
+import { DiagLogger, DiagLogFunction } from './types';
 
 const consoleMap: { n: keyof DiagLogger; c: keyof Console }[] = [
   { n: 'error', c: 'error' },
diff --git a/src/diag/index.ts b/src/diag/index.ts
new file mode 100644
index 00000000..751b5eed
--- /dev/null
+++ b/src/diag/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ *
+ * 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
+ *
+ *      https://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.
+ */
+
+export * from './consoleLogger';
+export * from './types';
diff --git a/src/diag/internal/logLevelLogger.ts b/src/diag/internal/logLevelLogger.ts
new file mode 100644
index 00000000..e9205b36
--- /dev/null
+++ b/src/diag/internal/logLevelLogger.ts
@@ -0,0 +1,51 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ *
+ * 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
+ *
+ *      https://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 { DiagLogFunction, DiagLogger, DiagLogLevel } from '../types';
+
+export function createLogLevelDiagLogger(
+  maxLevel: DiagLogLevel,
+  logger: DiagLogger
+): DiagLogger {
+  if (maxLevel < DiagLogLevel.NONE) {
+    maxLevel = DiagLogLevel.NONE;
+  } else if (maxLevel > DiagLogLevel.ALL) {
+    maxLevel = DiagLogLevel.ALL;
+  }
+
+  // In case the logger is null or undefined
+  logger = logger || {};
+
+  function _filterFunc(
+    funcName: keyof DiagLogger,
+    theLevel: DiagLogLevel
+  ): DiagLogFunction {
+    const theFunc = logger[funcName];
+
+    if (typeof theFunc === 'function' && maxLevel >= theLevel) {
+      return theFunc.bind(logger);
+    }
+    return function () {};
+  }
+
+  return {
+    error: _filterFunc('error', DiagLogLevel.ERROR),
+    warn: _filterFunc('warn', DiagLogLevel.WARN),
+    info: _filterFunc('info', DiagLogLevel.INFO),
+    debug: _filterFunc('debug', DiagLogLevel.DEBUG),
+    verbose: _filterFunc('verbose', DiagLogLevel.VERBOSE),
+  };
+}
diff --git a/src/diag/internal/noopLogger.ts b/src/diag/internal/noopLogger.ts
new file mode 100644
index 00000000..0c4e7d13
--- /dev/null
+++ b/src/diag/internal/noopLogger.ts
@@ -0,0 +1,34 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ *
+ * 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
+ *
+ *      https://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 { DiagLogger } from '../types';
+
+function noopLogFunction() {}
+
+/**
+ * Returns a No-Op Diagnostic logger where all messages do nothing.
+ * @implements {@link DiagLogger}
+ * @returns {DiagLogger}
+ */
+export function createNoopDiagLogger(): DiagLogger {
+  return {
+    verbose: noopLogFunction,
+    debug: noopLogFunction,
+    info: noopLogFunction,
+    warn: noopLogFunction,
+    error: noopLogFunction,
+  };
+}
diff --git a/src/diag/logLevel.ts b/src/diag/logLevel.ts
deleted file mode 100644
index 362bb135..00000000
--- a/src/diag/logLevel.ts
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- *
- * 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
- *
- *      https://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 { DiagAPI } from '../api/diag';
-import { DiagLogger, DiagLogFunction, createNoopDiagLogger } from './logger';
-
-/**
- * Defines the available internal logging levels for the diagnostic logger, the numeric values
- * of the levels are defined to match the original values from the initial LogLevel to avoid
- * compatibility/migration issues for any implementation that assume the numeric ordering.
- */
-export enum DiagLogLevel {
-  /** Diagnostic Logging level setting to disable all logging (except and forced logs) */
-  NONE = 0,
-
-  /** Identifies an error scenario */
-  ERROR = 30,
-
-  /** Identifies a warning scenario */
-  WARN = 50,
-
-  /** General informational log message */
-  INFO = 60,
-
-  /** General debug log message */
-  DEBUG = 70,
-
-  /**
-   * Detailed trace level logging should only be used for development, should only be set
-   * in a development environment.
-   */
-  VERBOSE = 80,
-
-  /** Used to set the logging level to include all logging */
-  ALL = 9999,
-}
-
-/**
- * This is equivalent to:
- * type LogLevelString = 'NONE' | 'ERROR' | 'WARN' | 'INFO' | 'DEBUG' | 'VERBOSE' | 'ALL';
- */
-export type DiagLogLevelString = keyof typeof DiagLogLevel;
-
-/** Mapping from DiagLogger function name to logging level. */
-const levelMap: { n: keyof DiagLogger; l: DiagLogLevel }[] = [
-  { n: 'error', l: DiagLogLevel.ERROR },
-  { n: 'warn', l: DiagLogLevel.WARN },
-  { n: 'info', l: DiagLogLevel.INFO },
-  { n: 'debug', l: DiagLogLevel.DEBUG },
-  { n: 'verbose', l: DiagLogLevel.VERBOSE },
-];
-
-/**
- * Create a Diagnostic logger which limits the messages that are logged via the wrapped logger based on whether the
- * message has a {@link DiagLogLevel} equal to the maximum logging level or lower, unless the {@link DiagLogLevel} is
- * NONE which will return a noop logger instance. This can be useful to reduce the amount of logging used for the
- * system or for a specific component based on any local configuration.
- * If you don't supply a logger it will use the global api.diag as the destination which will use the
- * current logger and any filtering it may have applied.
- * To avoid / bypass any global level filtering you should pass the current logger returned via
- * api.diag.getLogger() however, any changes to the logger used by api.diag won't be reflected for this case.
- * @param maxLevel - The max level to log any logging of a lower
- * @param logger - The specific logger to limit, if not defined or supplied will default to api.diag
- * @implements {@link DiagLogger}
- * @returns {DiagLogger}
- */
-
-export function createLogLevelDiagLogger(
-  maxLevel: DiagLogLevel,
-  logger?: DiagLogger | null
-): DiagLogger {
-  if (maxLevel < DiagLogLevel.NONE) {
-    maxLevel = DiagLogLevel.NONE;
-  } else if (maxLevel > DiagLogLevel.ALL) {
-    maxLevel = DiagLogLevel.ALL;
-  }
-
-  if (maxLevel === DiagLogLevel.NONE) {
-    return createNoopDiagLogger();
-  }
-
-  if (!logger) {
-    logger = DiagAPI.instance();
-  }
-
-  function _filterFunc(
-    theLogger: DiagLogger,
-    funcName: keyof DiagLogger,
-    theLevel: DiagLogLevel
-  ): DiagLogFunction {
-    if (maxLevel >= theLevel) {
-      return function () {
-        const orgArguments = arguments as unknown;
-        const theFunc = theLogger[funcName];
-        if (theFunc && typeof theFunc === 'function') {
-          return theFunc.apply(
-            logger,
-            orgArguments as Parameters<DiagLogFunction>
-          );
-        }
-      };
-    }
-    return function () {};
-  }
-
-  const newLogger = {} as DiagLogger;
-  for (let i = 0; i < levelMap.length; i++) {
-    const name = levelMap[i].n;
-    newLogger[name] = _filterFunc(logger, name, levelMap[i].l);
-  }
-
-  return newLogger;
-}
diff --git a/src/diag/logger.ts b/src/diag/types.ts
similarity index 74%
rename from src/diag/logger.ts
rename to src/diag/types.ts
index f718076b..3a633a5b 100644
--- a/src/diag/logger.ts
+++ b/src/diag/types.ts
@@ -59,28 +59,33 @@ export interface DiagLogger {
   verbose: DiagLogFunction;
 }
 
-// DiagLogger implementation
-export const diagLoggerFunctions: Array<keyof DiagLogger> = [
-  'verbose',
-  'debug',
-  'info',
-  'warn',
-  'error',
-];
-
-function noopLogFunction() {}
-
 /**
- * Returns a No-Op Diagnostic logger where all messages do nothing.
- * @implements {@link DiagLogger}
- * @returns {DiagLogger}
+ * Defines the available internal logging levels for the diagnostic logger, the numeric values
+ * of the levels are defined to match the original values from the initial LogLevel to avoid
+ * compatibility/migration issues for any implementation that assume the numeric ordering.
  */
-export function createNoopDiagLogger(): DiagLogger {
-  const diagLogger = {} as DiagLogger;
+export enum DiagLogLevel {
+  /** Diagnostic Logging level setting to disable all logging (except and forced logs) */
+  NONE = 0,
+
+  /** Identifies an error scenario */
+  ERROR = 30,
+
+  /** Identifies a warning scenario */
+  WARN = 50,
 
-  for (let i = 0; i < diagLoggerFunctions.length; i++) {
-    diagLogger[diagLoggerFunctions[i]] = noopLogFunction;
-  }
+  /** General informational log message */
+  INFO = 60,
+
+  /** General debug log message */
+  DEBUG = 70,
+
+  /**
+   * Detailed trace level logging should only be used for development, should only be set
+   * in a development environment.
+   */
+  VERBOSE = 80,
 
-  return diagLogger;
+  /** Used to set the logging level to include all logging */
+  ALL = 9999,
 }
diff --git a/src/index.ts b/src/index.ts
index 37d3b59e..b36eaccd 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
+export * from './baggage';
 export * from './common/Exception';
 export * from './common/Time';
-export * from './propagation/TextMapPropagator';
+export * from './diag';
 export * from './propagation/NoopTextMapPropagator';
-export * from './baggage';
+export * from './propagation/TextMapPropagator';
 export * from './trace/attributes';
 export * from './trace/Event';
 export * from './trace/link_context';
@@ -39,9 +40,6 @@ export * from './trace/trace_flags';
 export * from './trace/trace_state';
 export * from './trace/tracer_provider';
 export * from './trace/tracer';
-export * from './diag/consoleLogger';
-export * from './diag/logger';
-export * from './diag/logLevel';
 
 export {
   INVALID_SPANID,
diff --git a/test/api/api.test.ts b/test/api/api.test.ts
index 50b905be..5287b38c 100644
--- a/test/api/api.test.ts
+++ b/test/api/api.test.ts
@@ -32,12 +32,20 @@ import api, {
   defaultTextMapSetter,
   defaultTextMapGetter,
   diag,
-  diagLoggerFunctions,
 } from '../../src';
 import { DiagAPI } from '../../src/api/diag';
 import { _global } from '../../src/api/global-utils';
 import { NoopSpan } from '../../src/trace/NoopSpan';
 
+// DiagLogger implementation
+const diagLoggerFunctions = [
+  'verbose',
+  'debug',
+  'info',
+  'warn',
+  'error',
+] as const;
+
 describe('API', () => {
   it('should expose a tracer provider via getTracerProvider', () => {
     const tracer = api.trace.getTracerProvider();
@@ -191,6 +199,7 @@ describe('API', () => {
 
     diagLoggerFunctions.forEach(fName => {
       it(`no argument logger ${fName} message doesn't throw`, () => {
+        //@ts-expect-error an undefined logger is not allowed
         diag.setLogger();
         assert.doesNotThrow(() => {
           diag[fName](`${fName} message`);
diff --git a/test/diag/consoleLogger.test.ts b/test/diag/consoleLogger.test.ts
index 07269bc9..56b8e4c2 100644
--- a/test/diag/consoleLogger.test.ts
+++ b/test/diag/consoleLogger.test.ts
@@ -16,7 +16,14 @@
 
 import * as assert from 'assert';
 import { DiagConsoleLogger } from '../../src/diag/consoleLogger';
-import { diagLoggerFunctions } from '../../src/diag/logger';
+
+export const diagLoggerFunctions = [
+  'verbose',
+  'debug',
+  'info',
+  'warn',
+  'error',
+] as const;
 
 const consoleFuncs: Array<keyof Console> = [
   'debug',
diff --git a/test/diag/logLevel.test.ts b/test/diag/logLevel.test.ts
index 3b7fa548..3786fba9 100644
--- a/test/diag/logLevel.test.ts
+++ b/test/diag/logLevel.test.ts
@@ -16,23 +16,20 @@
 
 import * as assert from 'assert';
 import { diag } from '../../src';
-import {
-  createNoopDiagLogger,
-  DiagLogger,
-  diagLoggerFunctions,
-} from '../../src/diag/logger';
-import {
-  DiagLogLevel,
-  createLogLevelDiagLogger,
-} from '../../src/diag/logLevel';
+import { createLogLevelDiagLogger } from '../../src/diag/internal/logLevelLogger';
+import { createNoopDiagLogger } from '../../src/diag/internal/noopLogger';
+import { DiagLogger, DiagLogLevel } from '../../src/diag/types';
 
 // Matches the previous Logger definition
-const incompleteLoggerFuncs: Array<keyof DiagLogger> = [
+const incompleteLoggerFuncs = ['debug', 'info', 'warn', 'error'] as const;
+
+export const diagLoggerFunctions = [
+  'verbose',
   'debug',
   'info',
   'warn',
   'error',
-];
+] as const;
 
 describe('LogLevelFilter DiagLogger', () => {
   const calledArgs: any = {
@@ -50,8 +47,7 @@ describe('LogLevelFilter DiagLogger', () => {
 
   beforeEach(() => {
     // Set no logger so that sinon doesn't complain about TypeError: Attempted to wrap xxxx which is already wrapped
-    diag.setLogger();
-    diag.setLogLevel(DiagLogLevel.INFO);
+    diag.disable();
 
     // mock
     dummyLogger = {} as DiagLogger;
@@ -148,6 +144,7 @@ describe('LogLevelFilter DiagLogger', () => {
           });
 
           it('should be noop and not throw for null and no default Logger log', () => {
+            // @ts-expect-error null logger is not allowed
             const testLogger = createLogLevelDiagLogger(map.level, null);
             testLogger[fName](`${fName} called %s`, 'param1');
             diagLoggerFunctions.forEach(lName => {
@@ -156,6 +153,7 @@ describe('LogLevelFilter DiagLogger', () => {
           });
 
           it('should be noop and not throw for undefined and no default Logger log', () => {
+            // @ts-expect-error undefined logger is not allowed
             const testLogger = createLogLevelDiagLogger(map.level, undefined);
             testLogger[fName](`${fName} called %s`, 'param1');
             diagLoggerFunctions.forEach(lName => {
@@ -163,71 +161,14 @@ describe('LogLevelFilter DiagLogger', () => {
             });
           });
 
-          it('should use default logger for undefined and log', () => {
-            diag.setLogger(dummyLogger);
-            diag.setLogLevel(DiagLogLevel.ALL);
-            const testLogger = createLogLevelDiagLogger(map.level, undefined);
-            testLogger[fName](`${fName} called %s`, 'param1');
-            diagLoggerFunctions.forEach(lName => {
-              if (fName === lName && map.ignoreFuncs.indexOf(lName) === -1) {
-                assert.deepStrictEqual(calledArgs[lName], [
-                  `${fName} called %s`,
-                  'param1',
-                ]);
-              } else {
-                assert.strictEqual(calledArgs[lName], null);
-              }
-            });
-          });
-
-          it('should use default logger for null and log', () => {
-            diag.setLogger(dummyLogger);
-            diag.setLogLevel(DiagLogLevel.ALL);
-            const testLogger = createLogLevelDiagLogger(map.level, null);
-            testLogger[fName](`${fName} called %s`, 'param1');
-            diagLoggerFunctions.forEach(lName => {
-              if (fName === lName && map.ignoreFuncs.indexOf(lName) === -1) {
-                assert.deepStrictEqual(calledArgs[lName], [
-                  `${fName} called %s`,
-                  'param1',
-                ]);
-              } else {
-                assert.strictEqual(calledArgs[lName], null);
-              }
-            });
-          });
-
           levelMap.forEach(masterLevelMap => {
             describe(`when diag logger is set to ${masterLevelMap.message}`, () => {
-              it('diag setLogLevel is not ignored and using default logger', () => {
-                diag.setLogger(dummyLogger);
-                diag.setLogLevel(masterLevelMap.level);
-
-                const testLogger = createLogLevelDiagLogger(map.level);
-                testLogger[fName](`${fName} called %s`, 'param1');
-                diagLoggerFunctions.forEach(lName => {
-                  if (
-                    fName === lName &&
-                    map.ignoreFuncs.indexOf(lName) === -1 &&
-                    masterLevelMap.ignoreFuncs.indexOf(lName) === -1
-                  ) {
-                    assert.deepStrictEqual(calledArgs[lName], [
-                      `${fName} called %s`,
-                      'param1',
-                    ]);
-                  } else {
-                    assert.strictEqual(calledArgs[lName], null);
-                  }
-                });
-              });
-
-              it('diag setLogLevel is ignored when using a specific logger', () => {
-                diag.setLogger(dummyLogger);
-                diag.setLogLevel(masterLevelMap.level);
+              it('diag.setLogger level is ignored when using a specific logger', () => {
+                diag.setLogger(dummyLogger, masterLevelMap.level);
 
                 const testLogger = createLogLevelDiagLogger(
                   map.level,
-                  diag.getLogger()
+                  dummyLogger
                 );
                 testLogger[fName](`${fName} called %s`, 'param1');
                 diagLoggerFunctions.forEach(lName => {
@@ -247,9 +188,8 @@ describe('LogLevelFilter DiagLogger', () => {
             });
           });
 
-          it('diag setLogLevel and logger should log', () => {
-            diag.setLogger(dummyLogger);
-            diag.setLogLevel(map.level);
+          it('diag.setLogger level and logger should log', () => {
+            diag.setLogger(dummyLogger, map.level);
             diag[fName](`${fName} called %s`, 'param1');
             diagLoggerFunctions.forEach(lName => {
               if (fName === lName && map.ignoreFuncs.indexOf(lName) === -1) {
diff --git a/test/diag/logger.test.ts b/test/diag/logger.test.ts
index a957445b..308c2603 100644
--- a/test/diag/logger.test.ts
+++ b/test/diag/logger.test.ts
@@ -15,13 +15,18 @@
  */
 
 import * as assert from 'assert';
+import sinon = require('sinon');
 import { diag, DiagLogLevel } from '../../src';
-import {
-  DiagLogger,
-  createNoopDiagLogger,
-  diagLoggerFunctions,
-} from '../../src/diag/logger';
+import { createNoopDiagLogger } from '../../src/diag/internal/noopLogger';
+import { DiagLogger } from '../../src/diag/types';
 
+export const diagLoggerFunctions = [
+  'verbose',
+  'debug',
+  'info',
+  'warn',
+  'error',
+] as const;
 describe('DiagLogger functions', () => {
   const calledArgs: any = {
     error: null,
@@ -48,6 +53,7 @@ describe('DiagLogger functions', () => {
     diagLoggerFunctions.forEach(fName => {
       calledArgs[fName] = null;
     });
+    diag.disable();
   });
 
   describe('constructor', () => {
@@ -68,8 +74,7 @@ describe('DiagLogger functions', () => {
       });
 
       it(`diag should log with ${fName} message`, () => {
-        diag.setLogger(dummyLogger);
-        diag.setLogLevel(DiagLogLevel.ALL);
+        diag.setLogger(dummyLogger, DiagLogLevel.ALL);
         diag[fName](`${fName} called %s`, 'param1');
         diagLoggerFunctions.forEach(lName => {
           if (fName === lName) {
@@ -91,4 +96,27 @@ describe('DiagLogger functions', () => {
       });
     });
   });
+
+  describe('diag is used as the diag logger in setLogger', () => {
+    it('should not throw', () => {
+      diag.setLogger(diag);
+    });
+
+    it('should use the previously registered logger to log the error', () => {
+      const error = sinon.stub();
+      diag.setLogger({
+        verbose: () => {},
+        debug: () => {},
+        info: () => {},
+        warn: () => {},
+        error,
+      });
+
+      sinon.assert.notCalled(error);
+
+      diag.setLogger(diag);
+
+      sinon.assert.calledOnce(error);
+    });
+  });
 });
diff --git a/tsconfig.docs.json b/tsconfig.docs.json
deleted file mode 100644
index 0d2f7ed0..00000000
--- a/tsconfig.docs.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "compilerOptions": {
-    "rootDir": ".",
-    "outDir": "build"
-  },
-  "include": [
-    "src/**/*.ts"
-  ],
-  "typedocOptions": {
-    "name": "OpenTelemetry API for JavaScript",
-    "out": "docs/out",
-    "entryPoints": ["./src/index.ts"],
-    "hideGenerator": true
-  }
-}