@backstage/backend-defaults 0.12.1-next.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/config.d.ts +61 -1
- package/dist/PackageDiscoveryService.cjs.js +1 -1
- package/dist/PackageDiscoveryService.cjs.js.map +1 -1
- package/dist/cache.d.ts +8 -0
- package/dist/entrypoints/cache/CacheManager.cjs.js +13 -2
- package/dist/entrypoints/cache/CacheManager.cjs.js.map +1 -1
- package/dist/entrypoints/rootLogger/WinstonLogger.cjs.js +43 -3
- package/dist/entrypoints/rootLogger/WinstonLogger.cjs.js.map +1 -1
- package/dist/entrypoints/rootLogger/config.cjs.js +32 -0
- package/dist/entrypoints/rootLogger/config.cjs.js.map +1 -0
- package/dist/entrypoints/rootLogger/rootLoggerServiceFactory.cjs.js +13 -6
- package/dist/entrypoints/rootLogger/rootLoggerServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootLogger/types.cjs.js +8 -0
- package/dist/entrypoints/rootLogger/types.cjs.js.map +1 -0
- package/dist/entrypoints/rootLogger/utils.cjs.js +38 -0
- package/dist/entrypoints/rootLogger/utils.cjs.js.map +1 -0
- package/dist/package.json.cjs.js +1 -1
- package/dist/rootLogger.d.ts +25 -3
- package/package.json +17 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# @backstage/backend-defaults
|
|
2
2
|
|
|
3
|
+
## 0.12.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 33bd4d0: Deduplicate discovered features discovered with discoveryFeatureLoader
|
|
8
|
+
- 4eda590: Fixed cache namespace and key prefix separator configuration to properly use configured values instead of hardcoded plugin ID. The cache manager now correctly combines the configured namespace with plugin IDs using the configured separator for Redis and Valkey. Memcache and memory store continue to use plugin ID as namespace.
|
|
9
|
+
- f244e61: Add `backend.logger` config options to configure the `RootLoggerService`.
|
|
10
|
+
|
|
11
|
+
Read more about the new configuration options in the
|
|
12
|
+
[Root Logger Service](https://backstage.io/docs/backend-system/core-services/root-logger/)
|
|
13
|
+
documentation.
|
|
14
|
+
|
|
15
|
+
- Updated dependencies
|
|
16
|
+
- @backstage/config-loader@1.10.3
|
|
17
|
+
- @backstage/plugin-auth-node@0.6.7
|
|
18
|
+
- @backstage/plugin-events-node@0.4.15
|
|
19
|
+
- @backstage/integration@1.18.0
|
|
20
|
+
- @backstage/types@1.2.2
|
|
21
|
+
- @backstage/backend-app-api@1.2.7
|
|
22
|
+
- @backstage/backend-plugin-api@1.4.3
|
|
23
|
+
- @backstage/plugin-permission-node@0.10.4
|
|
24
|
+
|
|
25
|
+
## 0.12.1-next.1
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- 4eda590: Fixed cache namespace and key prefix separator configuration to properly use configured values instead of hardcoded plugin ID. The cache manager now correctly combines the configured namespace with plugin IDs using the configured separator for Redis and Valkey. Memcache and memory store continue to use plugin ID as namespace.
|
|
30
|
+
- Updated dependencies
|
|
31
|
+
- @backstage/config-loader@1.10.3-next.0
|
|
32
|
+
- @backstage/plugin-auth-node@0.6.7-next.1
|
|
33
|
+
- @backstage/integration@1.18.0-next.0
|
|
34
|
+
- @backstage/integration-aws-node@0.1.17
|
|
35
|
+
|
|
3
36
|
## 0.12.1-next.0
|
|
4
37
|
|
|
5
38
|
### Patch Changes
|
package/config.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { HumanDuration } from '@backstage/types';
|
|
17
|
+
import { HumanDuration, JsonObject } from '@backstage/types';
|
|
18
18
|
|
|
19
19
|
export interface Config {
|
|
20
20
|
app: {
|
|
@@ -985,6 +985,66 @@ export interface Config {
|
|
|
985
985
|
headers?: { [name: string]: string };
|
|
986
986
|
};
|
|
987
987
|
|
|
988
|
+
/**
|
|
989
|
+
* Options to configure the default RootLoggerService.
|
|
990
|
+
*/
|
|
991
|
+
logger?: {
|
|
992
|
+
/**
|
|
993
|
+
* Configures the global log level for messages.
|
|
994
|
+
*
|
|
995
|
+
* This can also be configured using the LOG_LEVEL environment variable, which
|
|
996
|
+
* takes precedence over this configuration.
|
|
997
|
+
*
|
|
998
|
+
* Defaults to 'info'.
|
|
999
|
+
*/
|
|
1000
|
+
level?: 'debug' | 'info' | 'warn' | 'error';
|
|
1001
|
+
|
|
1002
|
+
/**
|
|
1003
|
+
* Additional metadata to include with every log entry.
|
|
1004
|
+
*/
|
|
1005
|
+
meta?: JsonObject;
|
|
1006
|
+
|
|
1007
|
+
/**
|
|
1008
|
+
* List of logger overrides.
|
|
1009
|
+
*
|
|
1010
|
+
* Can be used to configure a different level for logs matching certain criterias.
|
|
1011
|
+
* For example, it can be used to ignore 'info' logs of given plugins.
|
|
1012
|
+
*
|
|
1013
|
+
* @example
|
|
1014
|
+
*
|
|
1015
|
+
* ```yaml
|
|
1016
|
+
* logger:
|
|
1017
|
+
* level: info
|
|
1018
|
+
* overrides:
|
|
1019
|
+
* # For catalog and auth plugins, messages less important than 'warn' will be ignored.
|
|
1020
|
+
* - matchers:
|
|
1021
|
+
* plugin: [catalog, auth]
|
|
1022
|
+
* level: warn
|
|
1023
|
+
* # Ignore all messages that starts with 'Forget'
|
|
1024
|
+
* - matchers:
|
|
1025
|
+
* message: '/^Forget/'
|
|
1026
|
+
* level: warn
|
|
1027
|
+
* ```
|
|
1028
|
+
*/
|
|
1029
|
+
overrides?: Array<{
|
|
1030
|
+
/**
|
|
1031
|
+
* Conditions that must be met to override the log level.
|
|
1032
|
+
*
|
|
1033
|
+
* A matcher can be:
|
|
1034
|
+
*
|
|
1035
|
+
* - A string (exact match or regex pattern delimited by slashes, e.g. `/pattern/`)
|
|
1036
|
+
* - A non-string value (compared by strict equality)
|
|
1037
|
+
* - An array of matchers (returns true if any matcher matches)
|
|
1038
|
+
*/
|
|
1039
|
+
matchers: JsonObject;
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* Log level to use for matched entries.
|
|
1043
|
+
*/
|
|
1044
|
+
level: 'debug' | 'info' | 'warn' | 'error';
|
|
1045
|
+
}>;
|
|
1046
|
+
};
|
|
1047
|
+
|
|
988
1048
|
/**
|
|
989
1049
|
* Rate limiting options. Defining this as `true` will enable rate limiting with default values.
|
|
990
1050
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PackageDiscoveryService.cjs.js","sources":["../src/PackageDiscoveryService.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport { resolve as resolvePath, dirname } from 'path';\n\nimport {\n BackendFeature,\n RootConfigService,\n RootLoggerService,\n} from '@backstage/backend-plugin-api';\nimport { BackstagePackageJson } from '@backstage/cli-node';\nimport { isError } from '@backstage/errors';\n\nconst DETECTED_PACKAGE_ROLES = [\n 'node-library',\n 'backend',\n 'backend-plugin',\n 'backend-plugin-module',\n];\n\n/** @internal */\nfunction isBackendFeature(value: unknown): value is BackendFeature {\n return (\n !!value &&\n ['object', 'function'].includes(typeof value) &&\n (value as BackendFeature).$$type === '@backstage/BackendFeature'\n );\n}\n\n/** @internal */\nfunction isBackendFeatureFactory(\n value: unknown,\n): value is () => BackendFeature {\n return (\n !!value &&\n typeof value === 'function' &&\n (value as any).$$type === '@backstage/BackendFeatureFactory'\n );\n}\n\n/** @internal */\nasync function findClosestPackageDir(\n searchDir: string,\n): Promise<string | undefined> {\n let path = searchDir;\n\n // Some confidence check to avoid infinite loop\n for (let i = 0; i < 1000; i++) {\n const packagePath = resolvePath(path, 'package.json');\n const exists = await fs.pathExists(packagePath);\n if (exists) {\n return path;\n }\n\n const newPath = dirname(path);\n if (newPath === path) {\n return undefined;\n }\n path = newPath;\n }\n\n throw new Error(\n `Iteration limit reached when searching for root package.json at ${searchDir}`,\n );\n}\n\n/** @internal */\nexport class PackageDiscoveryService {\n constructor(\n private readonly config: RootConfigService,\n private readonly logger: RootLoggerService,\n ) {}\n\n getDependencyNames(path: string) {\n const { dependencies } = require(path) as BackstagePackageJson;\n const packagesConfig = this.config.getOptional('backend.packages');\n\n const dependencyNames = Object.keys(dependencies || {});\n\n if (packagesConfig === 'all') {\n return dependencyNames;\n }\n\n const includedPackagesConfig = this.config.getOptionalStringArray(\n 'backend.packages.include',\n );\n\n const includedPackages = includedPackagesConfig\n ? new Set(includedPackagesConfig)\n : dependencyNames;\n const excludedPackagesSet = new Set(\n this.config.getOptionalStringArray('backend.packages.exclude'),\n );\n\n return [...includedPackages].filter(name => !excludedPackagesSet.has(name));\n }\n\n async getBackendFeatures(): Promise<{ features: Array<BackendFeature> }> {\n const packagesConfig = this.config.getOptional('backend.packages');\n if (!packagesConfig || Object.keys(packagesConfig).length === 0) {\n return { features: [] };\n }\n\n const packageDir = await findClosestPackageDir(process.argv[1]);\n if (!packageDir) {\n throw new Error('Package discovery failed to find package.json');\n }\n const dependencyNames = this.getDependencyNames(\n resolvePath(packageDir, 'package.json'),\n );\n\n const features: BackendFeature[] = [];\n\n for (const name of dependencyNames) {\n let depPkg: BackstagePackageJson;\n try {\n const packageJsonPath = require.resolve(`${name}/package.json`, {\n paths: [packageDir],\n });\n depPkg = require(packageJsonPath) as BackstagePackageJson;\n } catch (error) {\n // Handle packages with \"exports\" field that don't export ./package.json\n if (isError(error) && error.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED') {\n continue; // Skip packages that don't export package.json - they can't be Backstage packages\n }\n throw error;\n }\n if (\n !depPkg?.backstage?.role ||\n !DETECTED_PACKAGE_ROLES.includes(depPkg.backstage.role)\n ) {\n continue; // Not a backstage backend package, ignore\n }\n\n const exportedModulePaths = [\n require.resolve(name, {\n paths: [packageDir],\n }),\n ];\n\n // Find modules exported as alpha\n try {\n exportedModulePaths.push(\n require.resolve(`${name}/alpha`, { paths: [packageDir] }),\n );\n } catch {\n /* ignore */\n }\n\n for (const modulePath of exportedModulePaths) {\n const mod = require(modulePath);\n\n if (isBackendFeature(mod.default)) {\n this.logger.info(`Detected: ${name}`);\n features.push(mod.default);\n }\n if (isBackendFeatureFactory(mod.default)) {\n this.logger.info(`Detected: ${name}`);\n features.push(mod.default());\n }\n }\n }\n\n return { features };\n }\n}\n"],"names":["resolvePath","fs","dirname","isError"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"PackageDiscoveryService.cjs.js","sources":["../src/PackageDiscoveryService.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport { resolve as resolvePath, dirname } from 'path';\n\nimport {\n BackendFeature,\n RootConfigService,\n RootLoggerService,\n} from '@backstage/backend-plugin-api';\nimport { BackstagePackageJson } from '@backstage/cli-node';\nimport { isError } from '@backstage/errors';\n\nconst DETECTED_PACKAGE_ROLES = [\n 'node-library',\n 'backend',\n 'backend-plugin',\n 'backend-plugin-module',\n];\n\n/** @internal */\nfunction isBackendFeature(value: unknown): value is BackendFeature {\n return (\n !!value &&\n ['object', 'function'].includes(typeof value) &&\n (value as BackendFeature).$$type === '@backstage/BackendFeature'\n );\n}\n\n/** @internal */\nfunction isBackendFeatureFactory(\n value: unknown,\n): value is () => BackendFeature {\n return (\n !!value &&\n typeof value === 'function' &&\n (value as any).$$type === '@backstage/BackendFeatureFactory'\n );\n}\n\n/** @internal */\nasync function findClosestPackageDir(\n searchDir: string,\n): Promise<string | undefined> {\n let path = searchDir;\n\n // Some confidence check to avoid infinite loop\n for (let i = 0; i < 1000; i++) {\n const packagePath = resolvePath(path, 'package.json');\n const exists = await fs.pathExists(packagePath);\n if (exists) {\n return path;\n }\n\n const newPath = dirname(path);\n if (newPath === path) {\n return undefined;\n }\n path = newPath;\n }\n\n throw new Error(\n `Iteration limit reached when searching for root package.json at ${searchDir}`,\n );\n}\n\n/** @internal */\nexport class PackageDiscoveryService {\n constructor(\n private readonly config: RootConfigService,\n private readonly logger: RootLoggerService,\n ) {}\n\n getDependencyNames(path: string) {\n const { dependencies } = require(path) as BackstagePackageJson;\n const packagesConfig = this.config.getOptional('backend.packages');\n\n const dependencyNames = Object.keys(dependencies || {});\n\n if (packagesConfig === 'all') {\n return dependencyNames;\n }\n\n const includedPackagesConfig = this.config.getOptionalStringArray(\n 'backend.packages.include',\n );\n\n const includedPackages = includedPackagesConfig\n ? new Set(includedPackagesConfig)\n : dependencyNames;\n const excludedPackagesSet = new Set(\n this.config.getOptionalStringArray('backend.packages.exclude'),\n );\n\n return [...includedPackages].filter(name => !excludedPackagesSet.has(name));\n }\n\n async getBackendFeatures(): Promise<{ features: Array<BackendFeature> }> {\n const packagesConfig = this.config.getOptional('backend.packages');\n if (!packagesConfig || Object.keys(packagesConfig).length === 0) {\n return { features: [] };\n }\n\n const packageDir = await findClosestPackageDir(process.argv[1]);\n if (!packageDir) {\n throw new Error('Package discovery failed to find package.json');\n }\n const dependencyNames = this.getDependencyNames(\n resolvePath(packageDir, 'package.json'),\n );\n\n const features: BackendFeature[] = [];\n\n for (const name of dependencyNames) {\n let depPkg: BackstagePackageJson;\n try {\n const packageJsonPath = require.resolve(`${name}/package.json`, {\n paths: [packageDir],\n });\n depPkg = require(packageJsonPath) as BackstagePackageJson;\n } catch (error) {\n // Handle packages with \"exports\" field that don't export ./package.json\n if (isError(error) && error.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED') {\n continue; // Skip packages that don't export package.json - they can't be Backstage packages\n }\n throw error;\n }\n if (\n !depPkg?.backstage?.role ||\n !DETECTED_PACKAGE_ROLES.includes(depPkg.backstage.role)\n ) {\n continue; // Not a backstage backend package, ignore\n }\n\n const exportedModulePaths = [\n require.resolve(name, {\n paths: [packageDir],\n }),\n ];\n\n // Find modules exported as alpha\n try {\n exportedModulePaths.push(\n require.resolve(`${name}/alpha`, { paths: [packageDir] }),\n );\n } catch {\n /* ignore */\n }\n\n for (const modulePath of exportedModulePaths) {\n const mod = require(modulePath);\n\n if (isBackendFeature(mod.default)) {\n this.logger.info(`Detected: ${name}`);\n features.push(mod.default);\n }\n if (isBackendFeatureFactory(mod.default)) {\n this.logger.info(`Detected: ${name}`);\n features.push(mod.default());\n }\n }\n }\n\n return { features: Array.from(new Set(features)) };\n }\n}\n"],"names":["resolvePath","fs","dirname","isError"],"mappings":";;;;;;;;;;AA2BA,MAAM,sBAAA,GAAyB;AAAA,EAC7B,cAAA;AAAA,EACA,SAAA;AAAA,EACA,gBAAA;AAAA,EACA;AACF,CAAA;AAGA,SAAS,iBAAiB,KAAA,EAAyC;AACjE,EAAA,OACE,CAAC,CAAC,KAAA,IACF,CAAC,QAAA,EAAU,UAAU,CAAA,CAAE,QAAA,CAAS,OAAO,KAAK,CAAA,IAC3C,KAAA,CAAyB,MAAA,KAAW,2BAAA;AAEzC;AAGA,SAAS,wBACP,KAAA,EAC+B;AAC/B,EAAA,OACE,CAAC,CAAC,KAAA,IACF,OAAO,KAAA,KAAU,UAAA,IAChB,MAAc,MAAA,KAAW,kCAAA;AAE9B;AAGA,eAAe,sBACb,SAAA,EAC6B;AAC7B,EAAA,IAAI,IAAA,GAAO,SAAA;AAGX,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,EAAM,CAAA,EAAA,EAAK;AAC7B,IAAA,MAAM,WAAA,GAAcA,oBAAA,CAAY,IAAA,EAAM,cAAc,CAAA;AACpD,IAAA,MAAM,MAAA,GAAS,MAAMC,mBAAA,CAAG,UAAA,CAAW,WAAW,CAAA;AAC9C,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,OAAA,GAAUC,qBAAQ,IAAI,CAAA;AAC5B,IAAA,IAAI,YAAY,IAAA,EAAM;AACpB,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,IAAA,GAAO,OAAA;AAAA,EACT;AAEA,EAAA,MAAM,IAAI,KAAA;AAAA,IACR,mEAAmE,SAAS,CAAA;AAAA,GAC9E;AACF;AAGO,MAAM,uBAAA,CAAwB;AAAA,EACnC,WAAA,CACmB,QACA,MAAA,EACjB;AAFiB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAChB;AAAA,EAEH,mBAAmB,IAAA,EAAc;AAC/B,IAAA,MAAM,EAAE,YAAA,EAAa,GAAI,OAAA,CAAQ,IAAI,CAAA;AACrC,IAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,MAAA,CAAO,WAAA,CAAY,kBAAkB,CAAA;AAEjE,IAAA,MAAM,eAAA,GAAkB,MAAA,CAAO,IAAA,CAAK,YAAA,IAAgB,EAAE,CAAA;AAEtD,IAAA,IAAI,mBAAmB,KAAA,EAAO;AAC5B,MAAA,OAAO,eAAA;AAAA,IACT;AAEA,IAAA,MAAM,sBAAA,GAAyB,KAAK,MAAA,CAAO,sBAAA;AAAA,MACzC;AAAA,KACF;AAEA,IAAA,MAAM,gBAAA,GAAmB,sBAAA,GACrB,IAAI,GAAA,CAAI,sBAAsB,CAAA,GAC9B,eAAA;AACJ,IAAA,MAAM,sBAAsB,IAAI,GAAA;AAAA,MAC9B,IAAA,CAAK,MAAA,CAAO,sBAAA,CAAuB,0BAA0B;AAAA,KAC/D;AAEA,IAAA,OAAO,CAAC,GAAG,gBAAgB,CAAA,CAAE,MAAA,CAAO,UAAQ,CAAC,mBAAA,CAAoB,GAAA,CAAI,IAAI,CAAC,CAAA;AAAA,EAC5E;AAAA,EAEA,MAAM,kBAAA,GAAmE;AACvE,IAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,MAAA,CAAO,WAAA,CAAY,kBAAkB,CAAA;AACjE,IAAA,IAAI,CAAC,cAAA,IAAkB,MAAA,CAAO,KAAK,cAAc,CAAA,CAAE,WAAW,CAAA,EAAG;AAC/D,MAAA,OAAO,EAAE,QAAA,EAAU,EAAC,EAAE;AAAA,IACxB;AAEA,IAAA,MAAM,aAAa,MAAM,qBAAA,CAAsB,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAC,CAAA;AAC9D,IAAA,IAAI,CAAC,UAAA,EAAY;AACf,MAAA,MAAM,IAAI,MAAM,+CAA+C,CAAA;AAAA,IACjE;AACA,IAAA,MAAM,kBAAkB,IAAA,CAAK,kBAAA;AAAA,MAC3BF,oBAAA,CAAY,YAAY,cAAc;AAAA,KACxC;AAEA,IAAA,MAAM,WAA6B,EAAC;AAEpC,IAAA,KAAA,MAAW,QAAQ,eAAA,EAAiB;AAClC,MAAA,IAAI,MAAA;AACJ,MAAA,IAAI;AACF,QAAA,MAAM,eAAA,GAAkB,OAAA,CAAQ,OAAA,CAAQ,CAAA,EAAG,IAAI,CAAA,aAAA,CAAA,EAAiB;AAAA,UAC9D,KAAA,EAAO,CAAC,UAAU;AAAA,SACnB,CAAA;AACD,QAAA,MAAA,GAAS,QAAQ,eAAe,CAAA;AAAA,MAClC,SAAS,KAAA,EAAO;AAEd,QAAA,IAAIG,cAAA,CAAQ,KAAK,CAAA,IAAK,KAAA,CAAM,SAAS,+BAAA,EAAiC;AACpE,UAAA;AAAA,QACF;AACA,QAAA,MAAM,KAAA;AAAA,MACR;AACA,MAAA,IACE,CAAC,MAAA,EAAQ,SAAA,EAAW,IAAA,IACpB,CAAC,uBAAuB,QAAA,CAAS,MAAA,CAAO,SAAA,CAAU,IAAI,CAAA,EACtD;AACA,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,mBAAA,GAAsB;AAAA,QAC1B,OAAA,CAAQ,QAAQ,IAAA,EAAM;AAAA,UACpB,KAAA,EAAO,CAAC,UAAU;AAAA,SACnB;AAAA,OACH;AAGA,MAAA,IAAI;AACF,QAAA,mBAAA,CAAoB,IAAA;AAAA,UAClB,OAAA,CAAQ,OAAA,CAAQ,CAAA,EAAG,IAAI,CAAA,MAAA,CAAA,EAAU,EAAE,KAAA,EAAO,CAAC,UAAU,CAAA,EAAG;AAAA,SAC1D;AAAA,MACF,CAAA,CAAA,MAAQ;AAAA,MAER;AAEA,MAAA,KAAA,MAAW,cAAc,mBAAA,EAAqB;AAC5C,QAAA,MAAM,GAAA,GAAM,QAAQ,UAAU,CAAA;AAE9B,QAAA,IAAI,gBAAA,CAAiB,GAAA,CAAI,OAAO,CAAA,EAAG;AACjC,UAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAA,UAAA,EAAa,IAAI,CAAA,CAAE,CAAA;AACpC,UAAA,QAAA,CAAS,IAAA,CAAK,IAAI,OAAO,CAAA;AAAA,QAC3B;AACA,QAAA,IAAI,uBAAA,CAAwB,GAAA,CAAI,OAAO,CAAA,EAAG;AACxC,UAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAA,UAAA,EAAa,IAAI,CAAA,CAAE,CAAA;AACpC,UAAA,QAAA,CAAS,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS,CAAA;AAAA,QAC7B;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAO,EAAE,UAAU,KAAA,CAAM,IAAA,CAAK,IAAI,GAAA,CAAI,QAAQ,CAAC,CAAA,EAAE;AAAA,EACnD;AACF;;;;"}
|
package/dist/cache.d.ts
CHANGED
|
@@ -70,6 +70,14 @@ declare class CacheManager {
|
|
|
70
70
|
* Parse Redis-specific options from configuration.
|
|
71
71
|
*/
|
|
72
72
|
private static parseRedisOptions;
|
|
73
|
+
/**
|
|
74
|
+
* Construct the full namespace based on the options and pluginId.
|
|
75
|
+
*
|
|
76
|
+
* @param pluginId - The plugin ID to namespace
|
|
77
|
+
* @param storeOptions - Optional cache store configuration options
|
|
78
|
+
* @returns The constructed namespace string combining the configured namespace with pluginId
|
|
79
|
+
*/
|
|
80
|
+
private static constructNamespace;
|
|
73
81
|
/**
|
|
74
82
|
* Generates a PluginCacheManager for consumption by plugins.
|
|
75
83
|
*
|
|
@@ -141,6 +141,17 @@ class CacheManager {
|
|
|
141
141
|
}
|
|
142
142
|
return redisOptions;
|
|
143
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Construct the full namespace based on the options and pluginId.
|
|
146
|
+
*
|
|
147
|
+
* @param pluginId - The plugin ID to namespace
|
|
148
|
+
* @param storeOptions - Optional cache store configuration options
|
|
149
|
+
* @returns The constructed namespace string combining the configured namespace with pluginId
|
|
150
|
+
*/
|
|
151
|
+
static constructNamespace(pluginId, storeOptions) {
|
|
152
|
+
const prefix = storeOptions?.client?.namespace ? `${storeOptions.client.namespace}${storeOptions.client.keyPrefixSeparator ?? ":"}` : "";
|
|
153
|
+
return `${prefix}${pluginId}`;
|
|
154
|
+
}
|
|
144
155
|
/** @internal */
|
|
145
156
|
constructor(store, connectionString, errorHandler, logger, defaultTtl, storeOptions) {
|
|
146
157
|
if (!this.storeFactories.hasOwnProperty(store)) {
|
|
@@ -198,7 +209,7 @@ class CacheManager {
|
|
|
198
209
|
});
|
|
199
210
|
}
|
|
200
211
|
return new Keyv__default.default({
|
|
201
|
-
namespace: pluginId,
|
|
212
|
+
namespace: CacheManager.constructNamespace(pluginId, this.storeOptions),
|
|
202
213
|
ttl: defaultTtl,
|
|
203
214
|
store: stores[pluginId],
|
|
204
215
|
emitErrors: false,
|
|
@@ -232,7 +243,7 @@ class CacheManager {
|
|
|
232
243
|
});
|
|
233
244
|
}
|
|
234
245
|
return new Keyv__default.default({
|
|
235
|
-
namespace: pluginId,
|
|
246
|
+
namespace: CacheManager.constructNamespace(pluginId, this.storeOptions),
|
|
236
247
|
ttl: defaultTtl,
|
|
237
248
|
store: stores[pluginId],
|
|
238
249
|
emitErrors: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CacheManager.cjs.js","sources":["../../../src/entrypoints/cache/CacheManager.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CacheService,\n CacheServiceOptions,\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport Keyv from 'keyv';\nimport { DefaultCacheClient } from './CacheClient';\nimport {\n CacheManagerOptions,\n ttlToMilliseconds,\n CacheStoreOptions,\n RedisCacheStoreOptions,\n InfinispanClientBehaviorOptions,\n InfinispanServerConfig,\n} from './types';\nimport { InfinispanOptionsMapper } from './providers/infinispan/InfinispanOptionsMapper';\nimport { durationToMilliseconds } from '@backstage/types';\nimport { ConfigReader, readDurationFromConfig } from '@backstage/config';\nimport {\n InfinispanClientCacheInterface,\n InfinispanKeyvStore,\n} from './providers/infinispan/InfinispanKeyvStore';\n\ntype StoreFactory = (pluginId: string, defaultTtl: number | undefined) => Keyv;\n\n/**\n * Implements a Cache Manager which will automatically create new cache clients\n * for plugins when requested. All requested cache clients are created with the\n * connection details provided.\n *\n * @public\n */\nexport class CacheManager {\n /**\n * Keys represent supported `backend.cache.store` values, mapped to factories\n * that return Keyv instances appropriate to the store.\n */\n private readonly storeFactories = {\n redis: this.createRedisStoreFactory(),\n valkey: this.createValkeyStoreFactory(),\n memcache: this.createMemcacheStoreFactory(),\n memory: this.createMemoryStoreFactory(),\n infinispan: this.createInfinispanStoreFactory(),\n };\n\n private readonly logger?: LoggerService;\n private readonly store: keyof CacheManager['storeFactories'];\n private readonly connection: string;\n private readonly errorHandler: CacheManagerOptions['onError'];\n private readonly defaultTtl?: number;\n private readonly storeOptions?: CacheStoreOptions;\n\n /**\n * Creates a new {@link CacheManager} instance by reading from the `backend`\n * config section, specifically the `.cache` key.\n *\n * @param config - The loaded application configuration.\n * @param options - Optional configuration for the CacheManager.\n * @returns A new CacheManager instance.\n */\n static fromConfig(\n config: RootConfigService,\n options: CacheManagerOptions = {},\n ): CacheManager {\n // If no `backend.cache` config is provided, instantiate the CacheManager\n // with an in-memory cache client.\n const store = config.getOptionalString('backend.cache.store') || 'memory';\n const defaultTtlConfig = config.getOptional('backend.cache.defaultTtl');\n const connectionString =\n config.getOptionalString('backend.cache.connection') || '';\n const logger = options.logger?.child({\n type: 'cacheManager',\n });\n\n if (config.has('backend.cache.useRedisSets')) {\n logger?.warn(\n \"The 'backend.cache.useRedisSets' configuration key is deprecated and no longer has any effect. The underlying '@keyv/redis' and '@keyv/valkey' libraries no longer support redis sets.\",\n );\n }\n\n let defaultTtl: number | undefined;\n if (defaultTtlConfig !== undefined) {\n if (typeof defaultTtlConfig === 'number') {\n defaultTtl = defaultTtlConfig;\n } else {\n defaultTtl = durationToMilliseconds(\n readDurationFromConfig(config, { key: 'backend.cache.defaultTtl' }),\n );\n }\n }\n\n // Read store-specific options from config\n const storeOptions = CacheManager.parseStoreOptions(store, config, logger);\n\n return new CacheManager(\n store,\n connectionString,\n options.onError,\n logger,\n defaultTtl,\n storeOptions,\n );\n }\n\n /**\n * Parse store-specific options from configuration.\n *\n * @param store - The cache store type ('redis', 'valkey', 'memcache', 'infinispan', or 'memory')\n * @param config - The configuration service\n * @param logger - Optional logger for warnings\n * @returns The parsed store options\n */\n private static parseStoreOptions(\n store: string,\n config: RootConfigService,\n logger?: LoggerService,\n ): CacheStoreOptions | undefined {\n const storeConfigPath = `backend.cache.${store}`;\n\n if (!config.has(storeConfigPath)) {\n logger?.warn(\n `No configuration found for cache store '${store}' at '${storeConfigPath}'.`,\n );\n }\n\n if (store === 'redis' || store === 'valkey') {\n return CacheManager.parseRedisOptions(\n store,\n storeConfigPath,\n config,\n logger,\n );\n }\n\n if (store === 'infinispan') {\n return InfinispanOptionsMapper.parseInfinispanOptions(\n storeConfigPath,\n config,\n logger,\n );\n }\n\n return undefined;\n }\n\n /**\n * Parse Redis-specific options from configuration.\n */\n private static parseRedisOptions(\n store: string,\n storeConfigPath: string,\n config: RootConfigService,\n logger?: LoggerService,\n ): RedisCacheStoreOptions {\n const redisOptions: RedisCacheStoreOptions = {\n type: store as 'redis' | 'valkey',\n };\n\n const redisConfig =\n config.getOptionalConfig(storeConfigPath) ?? new ConfigReader({});\n\n redisOptions.client = {\n namespace: redisConfig.getOptionalString('client.namespace'),\n keyPrefixSeparator:\n redisConfig.getOptionalString('client.keyPrefixSeparator') || ':',\n clearBatchSize: redisConfig.getOptionalNumber('client.clearBatchSize'),\n useUnlink: redisConfig.getOptionalBoolean('client.useUnlink'),\n noNamespaceAffectsAll: redisConfig.getOptionalBoolean(\n 'client.noNamespaceAffectsAll',\n ),\n };\n\n if (redisConfig.has('cluster')) {\n const clusterConfig = redisConfig.getConfig('cluster');\n\n if (!clusterConfig.has('rootNodes')) {\n logger?.warn(\n `Redis cluster config has no 'rootNodes' key, defaulting to non-clustered mode`,\n );\n return redisOptions;\n }\n\n redisOptions.cluster = {\n rootNodes: clusterConfig.get('rootNodes'),\n defaults: clusterConfig.getOptional('defaults'),\n minimizeConnections: clusterConfig.getOptionalBoolean(\n 'minimizeConnections',\n ),\n useReplicas: clusterConfig.getOptionalBoolean('useReplicas'),\n maxCommandRedirections: clusterConfig.getOptionalNumber(\n 'maxCommandRedirections',\n ),\n };\n }\n\n return redisOptions;\n }\n\n /** @internal */\n constructor(\n store: string,\n connectionString: string,\n errorHandler: CacheManagerOptions['onError'],\n logger?: LoggerService,\n defaultTtl?: number,\n storeOptions?: CacheStoreOptions,\n ) {\n if (!this.storeFactories.hasOwnProperty(store)) {\n throw new Error(`Unknown cache store: ${store}`);\n }\n this.logger = logger;\n this.store = store as keyof CacheManager['storeFactories'];\n this.connection = connectionString;\n this.errorHandler = errorHandler;\n this.defaultTtl = defaultTtl;\n this.storeOptions = storeOptions;\n }\n\n /**\n * Generates a PluginCacheManager for consumption by plugins.\n *\n * @param pluginId - The plugin that the cache manager should be created for.\n * Plugin names should be unique.\n */\n forPlugin(pluginId: string): CacheService {\n const clientFactory = (options: CacheServiceOptions) => {\n const ttl = options.defaultTtl ?? this.defaultTtl;\n return this.getClientWithTtl(\n pluginId,\n ttl !== undefined ? ttlToMilliseconds(ttl) : undefined,\n );\n };\n\n return new DefaultCacheClient(clientFactory({}), clientFactory, {});\n }\n\n private getClientWithTtl(pluginId: string, ttl: number | undefined): Keyv {\n return this.storeFactories[this.store](pluginId, ttl);\n }\n\n private createRedisStoreFactory(): StoreFactory {\n const KeyvRedis = require('@keyv/redis').default;\n const { createCluster } = require('@keyv/redis');\n const stores: Record<string, typeof KeyvRedis> = {};\n\n return (pluginId, defaultTtl) => {\n if (this.storeOptions?.type !== 'redis') {\n throw new Error(\n `Internal error: Wrong config type passed to redis factory: ${this.storeOptions?.type}`,\n );\n }\n if (!stores[pluginId]) {\n const redisOptions = this.storeOptions?.client || {\n keyPrefixSeparator: ':',\n };\n if (this.storeOptions?.cluster) {\n // Create a Redis cluster\n const cluster = createCluster(this.storeOptions?.cluster);\n stores[pluginId] = new KeyvRedis(cluster, redisOptions);\n } else {\n // Create a regular Redis connection\n stores[pluginId] = new KeyvRedis(this.connection, redisOptions);\n }\n\n // Always provide an error handler to avoid stopping the process\n stores[pluginId].on('error', (err: Error) => {\n this.logger?.error('Failed to create redis cache client', err);\n this.errorHandler?.(err);\n });\n }\n return new Keyv({\n namespace: pluginId,\n ttl: defaultTtl,\n store: stores[pluginId],\n emitErrors: false,\n useKeyPrefix: false,\n });\n };\n }\n\n private createValkeyStoreFactory(): StoreFactory {\n const KeyvValkey = require('@keyv/valkey').default;\n const { createCluster } = require('@keyv/valkey');\n const stores: Record<string, typeof KeyvValkey> = {};\n\n return (pluginId, defaultTtl) => {\n if (this.storeOptions?.type !== 'valkey') {\n throw new Error(\n `Internal error: Wrong config type passed to valkey factory: ${this.storeOptions?.type}`,\n );\n }\n if (!stores[pluginId]) {\n const valkeyOptions = this.storeOptions?.client || {\n keyPrefixSeparator: ':',\n };\n if (this.storeOptions?.cluster) {\n // Create a Valkey cluster (Redis cluster under the hood)\n const cluster = createCluster(this.storeOptions?.cluster);\n stores[pluginId] = new KeyvValkey(cluster, valkeyOptions);\n } else {\n // Create a regular Valkey connection\n stores[pluginId] = new KeyvValkey(this.connection, valkeyOptions);\n }\n\n // Always provide an error handler to avoid stopping the process\n stores[pluginId].on('error', (err: Error) => {\n this.logger?.error('Failed to create valkey cache client', err);\n this.errorHandler?.(err);\n });\n }\n return new Keyv({\n namespace: pluginId,\n ttl: defaultTtl,\n store: stores[pluginId],\n emitErrors: false,\n useKeyPrefix: false,\n });\n };\n }\n\n private createMemcacheStoreFactory(): StoreFactory {\n const KeyvMemcache = require('@keyv/memcache').default;\n const stores: Record<string, typeof KeyvMemcache> = {};\n\n return (pluginId, defaultTtl) => {\n if (!stores[pluginId]) {\n stores[pluginId] = new KeyvMemcache(this.connection);\n // Always provide an error handler to avoid stopping the process\n stores[pluginId].on('error', (err: Error) => {\n this.logger?.error('Failed to create memcache cache client', err);\n this.errorHandler?.(err);\n });\n }\n return new Keyv({\n namespace: pluginId,\n ttl: defaultTtl,\n emitErrors: false,\n store: stores[pluginId],\n });\n };\n }\n\n private createMemoryStoreFactory(): StoreFactory {\n const store = new Map();\n return (pluginId, defaultTtl) =>\n new Keyv({\n namespace: pluginId,\n ttl: defaultTtl,\n emitErrors: false,\n store,\n });\n }\n\n private createInfinispanStoreFactory(): StoreFactory {\n const stores: Record<string, InfinispanKeyvStore> = {};\n\n return (pluginId, defaultTtl) => {\n if (this.storeOptions?.type !== 'infinispan') {\n throw new Error(\n `Internal error: Wrong config type passed to infinispan factory: ${this.storeOptions?.type}`,\n );\n }\n\n if (!stores[pluginId]) {\n // Use sync version for testing environments\n const isTest =\n process.env.NODE_ENV === 'test' || typeof jest !== 'undefined';\n\n // Create the client promise ONCE and reuse it\n const clientPromise: Promise<InfinispanClientCacheInterface> = isTest\n ? this.createInfinispanClientSync()\n : this.createInfinispanClientAsync();\n\n this.logger?.info(\n `Creating Infinispan cache client for plugin ${pluginId} isTest = ${isTest}`,\n );\n const storeInstance = new InfinispanKeyvStore({\n clientPromise,\n logger: this.logger!,\n });\n\n stores[pluginId] = storeInstance;\n\n // Always provide an error handler to avoid stopping the process\n storeInstance.on('error', (err: Error) => {\n this.logger?.error('Failed to create infinispan cache client', err);\n this.errorHandler?.(err);\n });\n }\n\n return new Keyv({\n namespace: pluginId,\n ttl: defaultTtl,\n store: stores[pluginId],\n emitErrors: false,\n });\n };\n }\n\n /**\n * Creates an Infinispan client using dynamic import (production use).\n * @returns Promise that resolves to an Infinispan client\n */\n private async createInfinispanClientAsync(): Promise<InfinispanClientCacheInterface> {\n return this.createInfinispanClient(false);\n }\n\n /**\n * Creates an Infinispan client using synchronous import (testing purposes).\n * @returns Promise that resolves to an Infinispan client\n */\n private createInfinispanClientSync(): Promise<InfinispanClientCacheInterface> {\n return this.createInfinispanClient(true);\n }\n\n /**\n * Creates an Infinispan client based on the provided configuration.\n * @param useSync - Whether to use synchronous import (for testing) or dynamic import\n * @returns Promise that resolves to an Infinispan client\n */\n private async createInfinispanClient(\n useSync: boolean = false,\n ): Promise<InfinispanClientCacheInterface> {\n try {\n this.logger?.info('Creating Infinispan client');\n\n if (this.storeOptions?.type === 'infinispan') {\n // Import infinispan based on the useSync parameter\n const infinispan = useSync\n ? require('infinispan')\n : await import('infinispan');\n\n const client = await infinispan.client(\n this.storeOptions.servers as InfinispanServerConfig[],\n this.storeOptions.options as InfinispanClientBehaviorOptions,\n );\n\n this.logger?.info('Infinispan client created successfully');\n return client;\n }\n throw new Error('Infinispan store options are not defined');\n } catch (error: any) {\n this.logger?.error('Failed to create Infinispan client', {\n error: error.message,\n });\n throw error;\n }\n }\n}\n"],"names":["config","durationToMilliseconds","readDurationFromConfig","InfinispanOptionsMapper","ConfigReader","ttlToMilliseconds","DefaultCacheClient","Keyv","InfinispanKeyvStore"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CacheManager.cjs.js","sources":["../../../src/entrypoints/cache/CacheManager.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CacheService,\n CacheServiceOptions,\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport Keyv from 'keyv';\nimport { DefaultCacheClient } from './CacheClient';\nimport {\n CacheManagerOptions,\n ttlToMilliseconds,\n CacheStoreOptions,\n RedisCacheStoreOptions,\n InfinispanClientBehaviorOptions,\n InfinispanServerConfig,\n} from './types';\nimport { InfinispanOptionsMapper } from './providers/infinispan/InfinispanOptionsMapper';\nimport { durationToMilliseconds } from '@backstage/types';\nimport { ConfigReader, readDurationFromConfig } from '@backstage/config';\nimport {\n InfinispanClientCacheInterface,\n InfinispanKeyvStore,\n} from './providers/infinispan/InfinispanKeyvStore';\n\ntype StoreFactory = (pluginId: string, defaultTtl: number | undefined) => Keyv;\n\n/**\n * Implements a Cache Manager which will automatically create new cache clients\n * for plugins when requested. All requested cache clients are created with the\n * connection details provided.\n *\n * @public\n */\nexport class CacheManager {\n /**\n * Keys represent supported `backend.cache.store` values, mapped to factories\n * that return Keyv instances appropriate to the store.\n */\n private readonly storeFactories = {\n redis: this.createRedisStoreFactory(),\n valkey: this.createValkeyStoreFactory(),\n memcache: this.createMemcacheStoreFactory(),\n memory: this.createMemoryStoreFactory(),\n infinispan: this.createInfinispanStoreFactory(),\n };\n\n private readonly logger?: LoggerService;\n private readonly store: keyof CacheManager['storeFactories'];\n private readonly connection: string;\n private readonly errorHandler: CacheManagerOptions['onError'];\n private readonly defaultTtl?: number;\n private readonly storeOptions?: CacheStoreOptions;\n\n /**\n * Creates a new {@link CacheManager} instance by reading from the `backend`\n * config section, specifically the `.cache` key.\n *\n * @param config - The loaded application configuration.\n * @param options - Optional configuration for the CacheManager.\n * @returns A new CacheManager instance.\n */\n static fromConfig(\n config: RootConfigService,\n options: CacheManagerOptions = {},\n ): CacheManager {\n // If no `backend.cache` config is provided, instantiate the CacheManager\n // with an in-memory cache client.\n const store = config.getOptionalString('backend.cache.store') || 'memory';\n const defaultTtlConfig = config.getOptional('backend.cache.defaultTtl');\n const connectionString =\n config.getOptionalString('backend.cache.connection') || '';\n const logger = options.logger?.child({\n type: 'cacheManager',\n });\n\n if (config.has('backend.cache.useRedisSets')) {\n logger?.warn(\n \"The 'backend.cache.useRedisSets' configuration key is deprecated and no longer has any effect. The underlying '@keyv/redis' and '@keyv/valkey' libraries no longer support redis sets.\",\n );\n }\n\n let defaultTtl: number | undefined;\n if (defaultTtlConfig !== undefined) {\n if (typeof defaultTtlConfig === 'number') {\n defaultTtl = defaultTtlConfig;\n } else {\n defaultTtl = durationToMilliseconds(\n readDurationFromConfig(config, { key: 'backend.cache.defaultTtl' }),\n );\n }\n }\n\n // Read store-specific options from config\n const storeOptions = CacheManager.parseStoreOptions(store, config, logger);\n\n return new CacheManager(\n store,\n connectionString,\n options.onError,\n logger,\n defaultTtl,\n storeOptions,\n );\n }\n\n /**\n * Parse store-specific options from configuration.\n *\n * @param store - The cache store type ('redis', 'valkey', 'memcache', 'infinispan', or 'memory')\n * @param config - The configuration service\n * @param logger - Optional logger for warnings\n * @returns The parsed store options\n */\n private static parseStoreOptions(\n store: string,\n config: RootConfigService,\n logger?: LoggerService,\n ): CacheStoreOptions | undefined {\n const storeConfigPath = `backend.cache.${store}`;\n\n if (!config.has(storeConfigPath)) {\n logger?.warn(\n `No configuration found for cache store '${store}' at '${storeConfigPath}'.`,\n );\n }\n\n if (store === 'redis' || store === 'valkey') {\n return CacheManager.parseRedisOptions(\n store,\n storeConfigPath,\n config,\n logger,\n );\n }\n\n if (store === 'infinispan') {\n return InfinispanOptionsMapper.parseInfinispanOptions(\n storeConfigPath,\n config,\n logger,\n );\n }\n\n return undefined;\n }\n\n /**\n * Parse Redis-specific options from configuration.\n */\n private static parseRedisOptions(\n store: string,\n storeConfigPath: string,\n config: RootConfigService,\n logger?: LoggerService,\n ): RedisCacheStoreOptions {\n const redisOptions: RedisCacheStoreOptions = {\n type: store as 'redis' | 'valkey',\n };\n\n const redisConfig =\n config.getOptionalConfig(storeConfigPath) ?? new ConfigReader({});\n\n redisOptions.client = {\n namespace: redisConfig.getOptionalString('client.namespace'),\n keyPrefixSeparator:\n redisConfig.getOptionalString('client.keyPrefixSeparator') || ':',\n clearBatchSize: redisConfig.getOptionalNumber('client.clearBatchSize'),\n useUnlink: redisConfig.getOptionalBoolean('client.useUnlink'),\n noNamespaceAffectsAll: redisConfig.getOptionalBoolean(\n 'client.noNamespaceAffectsAll',\n ),\n };\n\n if (redisConfig.has('cluster')) {\n const clusterConfig = redisConfig.getConfig('cluster');\n\n if (!clusterConfig.has('rootNodes')) {\n logger?.warn(\n `Redis cluster config has no 'rootNodes' key, defaulting to non-clustered mode`,\n );\n return redisOptions;\n }\n\n redisOptions.cluster = {\n rootNodes: clusterConfig.get('rootNodes'),\n defaults: clusterConfig.getOptional('defaults'),\n minimizeConnections: clusterConfig.getOptionalBoolean(\n 'minimizeConnections',\n ),\n useReplicas: clusterConfig.getOptionalBoolean('useReplicas'),\n maxCommandRedirections: clusterConfig.getOptionalNumber(\n 'maxCommandRedirections',\n ),\n };\n }\n\n return redisOptions;\n }\n\n /**\n * Construct the full namespace based on the options and pluginId.\n *\n * @param pluginId - The plugin ID to namespace\n * @param storeOptions - Optional cache store configuration options\n * @returns The constructed namespace string combining the configured namespace with pluginId\n */\n private static constructNamespace(\n pluginId: string,\n storeOptions: RedisCacheStoreOptions | undefined,\n ): string {\n const prefix = storeOptions?.client?.namespace\n ? `${storeOptions.client.namespace}${\n storeOptions.client.keyPrefixSeparator ?? ':'\n }`\n : '';\n\n return `${prefix}${pluginId}`;\n }\n\n /** @internal */\n constructor(\n store: string,\n connectionString: string,\n errorHandler: CacheManagerOptions['onError'],\n logger?: LoggerService,\n defaultTtl?: number,\n storeOptions?: CacheStoreOptions,\n ) {\n if (!this.storeFactories.hasOwnProperty(store)) {\n throw new Error(`Unknown cache store: ${store}`);\n }\n this.logger = logger;\n this.store = store as keyof CacheManager['storeFactories'];\n this.connection = connectionString;\n this.errorHandler = errorHandler;\n this.defaultTtl = defaultTtl;\n this.storeOptions = storeOptions;\n }\n\n /**\n * Generates a PluginCacheManager for consumption by plugins.\n *\n * @param pluginId - The plugin that the cache manager should be created for.\n * Plugin names should be unique.\n */\n forPlugin(pluginId: string): CacheService {\n const clientFactory = (options: CacheServiceOptions) => {\n const ttl = options.defaultTtl ?? this.defaultTtl;\n return this.getClientWithTtl(\n pluginId,\n ttl !== undefined ? ttlToMilliseconds(ttl) : undefined,\n );\n };\n\n return new DefaultCacheClient(clientFactory({}), clientFactory, {});\n }\n\n private getClientWithTtl(pluginId: string, ttl: number | undefined): Keyv {\n return this.storeFactories[this.store](pluginId, ttl);\n }\n\n private createRedisStoreFactory(): StoreFactory {\n const KeyvRedis = require('@keyv/redis').default;\n const { createCluster } = require('@keyv/redis');\n const stores: Record<string, typeof KeyvRedis> = {};\n\n return (pluginId, defaultTtl) => {\n if (this.storeOptions?.type !== 'redis') {\n throw new Error(\n `Internal error: Wrong config type passed to redis factory: ${this.storeOptions?.type}`,\n );\n }\n if (!stores[pluginId]) {\n const redisOptions = this.storeOptions?.client || {\n keyPrefixSeparator: ':',\n };\n if (this.storeOptions?.cluster) {\n // Create a Redis cluster\n const cluster = createCluster(this.storeOptions?.cluster);\n stores[pluginId] = new KeyvRedis(cluster, redisOptions);\n } else {\n // Create a regular Redis connection\n stores[pluginId] = new KeyvRedis(this.connection, redisOptions);\n }\n\n // Always provide an error handler to avoid stopping the process\n stores[pluginId].on('error', (err: Error) => {\n this.logger?.error('Failed to create redis cache client', err);\n this.errorHandler?.(err);\n });\n }\n return new Keyv({\n namespace: CacheManager.constructNamespace(pluginId, this.storeOptions),\n ttl: defaultTtl,\n store: stores[pluginId],\n emitErrors: false,\n useKeyPrefix: false,\n });\n };\n }\n\n private createValkeyStoreFactory(): StoreFactory {\n const KeyvValkey = require('@keyv/valkey').default;\n const { createCluster } = require('@keyv/valkey');\n const stores: Record<string, typeof KeyvValkey> = {};\n\n return (pluginId, defaultTtl) => {\n if (this.storeOptions?.type !== 'valkey') {\n throw new Error(\n `Internal error: Wrong config type passed to valkey factory: ${this.storeOptions?.type}`,\n );\n }\n if (!stores[pluginId]) {\n const valkeyOptions = this.storeOptions?.client || {\n keyPrefixSeparator: ':',\n };\n if (this.storeOptions?.cluster) {\n // Create a Valkey cluster (Redis cluster under the hood)\n const cluster = createCluster(this.storeOptions?.cluster);\n stores[pluginId] = new KeyvValkey(cluster, valkeyOptions);\n } else {\n // Create a regular Valkey connection\n stores[pluginId] = new KeyvValkey(this.connection, valkeyOptions);\n }\n\n // Always provide an error handler to avoid stopping the process\n stores[pluginId].on('error', (err: Error) => {\n this.logger?.error('Failed to create valkey cache client', err);\n this.errorHandler?.(err);\n });\n }\n return new Keyv({\n namespace: CacheManager.constructNamespace(pluginId, this.storeOptions),\n ttl: defaultTtl,\n store: stores[pluginId],\n emitErrors: false,\n useKeyPrefix: false,\n });\n };\n }\n\n private createMemcacheStoreFactory(): StoreFactory {\n const KeyvMemcache = require('@keyv/memcache').default;\n const stores: Record<string, typeof KeyvMemcache> = {};\n\n return (pluginId, defaultTtl) => {\n if (!stores[pluginId]) {\n stores[pluginId] = new KeyvMemcache(this.connection);\n // Always provide an error handler to avoid stopping the process\n stores[pluginId].on('error', (err: Error) => {\n this.logger?.error('Failed to create memcache cache client', err);\n this.errorHandler?.(err);\n });\n }\n return new Keyv({\n namespace: pluginId,\n ttl: defaultTtl,\n emitErrors: false,\n store: stores[pluginId],\n });\n };\n }\n\n private createMemoryStoreFactory(): StoreFactory {\n const store = new Map();\n return (pluginId, defaultTtl) =>\n new Keyv({\n namespace: pluginId,\n ttl: defaultTtl,\n emitErrors: false,\n store,\n });\n }\n\n private createInfinispanStoreFactory(): StoreFactory {\n const stores: Record<string, InfinispanKeyvStore> = {};\n\n return (pluginId, defaultTtl) => {\n if (this.storeOptions?.type !== 'infinispan') {\n throw new Error(\n `Internal error: Wrong config type passed to infinispan factory: ${this.storeOptions?.type}`,\n );\n }\n\n if (!stores[pluginId]) {\n // Use sync version for testing environments\n const isTest =\n process.env.NODE_ENV === 'test' || typeof jest !== 'undefined';\n\n // Create the client promise ONCE and reuse it\n const clientPromise: Promise<InfinispanClientCacheInterface> = isTest\n ? this.createInfinispanClientSync()\n : this.createInfinispanClientAsync();\n\n this.logger?.info(\n `Creating Infinispan cache client for plugin ${pluginId} isTest = ${isTest}`,\n );\n const storeInstance = new InfinispanKeyvStore({\n clientPromise,\n logger: this.logger!,\n });\n\n stores[pluginId] = storeInstance;\n\n // Always provide an error handler to avoid stopping the process\n storeInstance.on('error', (err: Error) => {\n this.logger?.error('Failed to create infinispan cache client', err);\n this.errorHandler?.(err);\n });\n }\n\n return new Keyv({\n namespace: pluginId,\n ttl: defaultTtl,\n store: stores[pluginId],\n emitErrors: false,\n });\n };\n }\n\n /**\n * Creates an Infinispan client using dynamic import (production use).\n * @returns Promise that resolves to an Infinispan client\n */\n private async createInfinispanClientAsync(): Promise<InfinispanClientCacheInterface> {\n return this.createInfinispanClient(false);\n }\n\n /**\n * Creates an Infinispan client using synchronous import (testing purposes).\n * @returns Promise that resolves to an Infinispan client\n */\n private createInfinispanClientSync(): Promise<InfinispanClientCacheInterface> {\n return this.createInfinispanClient(true);\n }\n\n /**\n * Creates an Infinispan client based on the provided configuration.\n * @param useSync - Whether to use synchronous import (for testing) or dynamic import\n * @returns Promise that resolves to an Infinispan client\n */\n private async createInfinispanClient(\n useSync: boolean = false,\n ): Promise<InfinispanClientCacheInterface> {\n try {\n this.logger?.info('Creating Infinispan client');\n\n if (this.storeOptions?.type === 'infinispan') {\n // Import infinispan based on the useSync parameter\n const infinispan = useSync\n ? require('infinispan')\n : await import('infinispan');\n\n const client = await infinispan.client(\n this.storeOptions.servers as InfinispanServerConfig[],\n this.storeOptions.options as InfinispanClientBehaviorOptions,\n );\n\n this.logger?.info('Infinispan client created successfully');\n return client;\n }\n throw new Error('Infinispan store options are not defined');\n } catch (error: any) {\n this.logger?.error('Failed to create Infinispan client', {\n error: error.message,\n });\n throw error;\n }\n }\n}\n"],"names":["config","durationToMilliseconds","readDurationFromConfig","InfinispanOptionsMapper","ConfigReader","ttlToMilliseconds","DefaultCacheClient","Keyv","InfinispanKeyvStore"],"mappings":"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"}
|
|
@@ -3,19 +3,26 @@
|
|
|
3
3
|
var winston = require('winston');
|
|
4
4
|
var tripleBeam = require('triple-beam');
|
|
5
5
|
var escapeRegExp = require('../../lib/escapeRegExp.cjs.js');
|
|
6
|
+
var types = require('./types.cjs.js');
|
|
7
|
+
var utils = require('./utils.cjs.js');
|
|
6
8
|
|
|
7
9
|
class WinstonLogger {
|
|
8
10
|
#winston;
|
|
9
11
|
#addRedactions;
|
|
12
|
+
#setLevelOverrides;
|
|
10
13
|
/**
|
|
11
14
|
* Creates a {@link WinstonLogger} instance.
|
|
12
15
|
*/
|
|
13
16
|
static create(options) {
|
|
17
|
+
const defaultLogLevel = process.env.LOG_LEVEL || options.level || "info";
|
|
14
18
|
const redacter = WinstonLogger.redacter();
|
|
19
|
+
const logLevelFilter = WinstonLogger.logLevelFilter(defaultLogLevel);
|
|
15
20
|
const defaultFormatter = process.env.NODE_ENV === "production" ? winston.format.json() : WinstonLogger.colorFormat();
|
|
16
21
|
let logger = winston.createLogger({
|
|
17
|
-
level
|
|
22
|
+
// Lowest level possible as we let the logLevelFilter do the filtering
|
|
23
|
+
level: "silly",
|
|
18
24
|
format: winston.format.combine(
|
|
25
|
+
logLevelFilter.format,
|
|
19
26
|
options.format ?? defaultFormatter,
|
|
20
27
|
redacter.format
|
|
21
28
|
),
|
|
@@ -24,7 +31,7 @@ class WinstonLogger {
|
|
|
24
31
|
if (options.meta) {
|
|
25
32
|
logger = logger.child(options.meta);
|
|
26
33
|
}
|
|
27
|
-
return new WinstonLogger(logger, redacter.add);
|
|
34
|
+
return new WinstonLogger(logger, redacter.add, logLevelFilter.setOverrides);
|
|
28
35
|
}
|
|
29
36
|
/**
|
|
30
37
|
* Creates a winston log formatter for redacting secrets.
|
|
@@ -95,9 +102,39 @@ class WinstonLogger {
|
|
|
95
102
|
})
|
|
96
103
|
);
|
|
97
104
|
}
|
|
98
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Formatter that filters log levels using overrides, falling back to the default level when no criteria match.
|
|
107
|
+
*/
|
|
108
|
+
static logLevelFilter(defaultLogLevel) {
|
|
109
|
+
const overrides = [];
|
|
110
|
+
return {
|
|
111
|
+
format: winston.format((log) => {
|
|
112
|
+
for (const override of overrides) {
|
|
113
|
+
if (override.predicate(log)) {
|
|
114
|
+
if (types.winstonLevels[log.level] > types.winstonLevels[override.level]) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
return log;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (types.winstonLevels[log.level] > types.winstonLevels[defaultLogLevel]) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
return log;
|
|
124
|
+
})(),
|
|
125
|
+
setOverrides: (newOverrides) => {
|
|
126
|
+
const newOverridesPredicates = newOverrides.map((o) => ({
|
|
127
|
+
predicate: utils.createLogMatcher(o.matchers),
|
|
128
|
+
level: o.level
|
|
129
|
+
}));
|
|
130
|
+
overrides.splice(0, overrides.length, ...newOverridesPredicates);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
constructor(winston, addRedactions, setLevelOverrides) {
|
|
99
135
|
this.#winston = winston;
|
|
100
136
|
this.#addRedactions = addRedactions;
|
|
137
|
+
this.#setLevelOverrides = setLevelOverrides;
|
|
101
138
|
}
|
|
102
139
|
error(message, meta) {
|
|
103
140
|
this.#winston.error(message, meta);
|
|
@@ -117,6 +154,9 @@ class WinstonLogger {
|
|
|
117
154
|
addRedactions(redactions) {
|
|
118
155
|
this.#addRedactions?.(redactions);
|
|
119
156
|
}
|
|
157
|
+
setLevelOverrides(overrides) {
|
|
158
|
+
this.#setLevelOverrides?.(overrides);
|
|
159
|
+
}
|
|
120
160
|
}
|
|
121
161
|
|
|
122
162
|
exports.WinstonLogger = WinstonLogger;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WinstonLogger.cjs.js","sources":["../../../src/entrypoints/rootLogger/WinstonLogger.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n LoggerService,\n RootLoggerService,\n} from '@backstage/backend-plugin-api';\nimport { JsonObject } from '@backstage/types';\nimport { Format, TransformableInfo } from 'logform';\nimport {\n Logger,\n format,\n createLogger,\n transports,\n transport as Transport,\n} from 'winston';\nimport { MESSAGE } from 'triple-beam';\nimport { escapeRegExp } from '../../lib/escapeRegExp';\n\n/**\n * @public\n */\nexport interface WinstonLoggerOptions {\n meta?: JsonObject;\n level?: string;\n format?: Format;\n transports?: Transport[];\n}\n\n/**\n * A {@link @backstage/backend-plugin-api#LoggerService} implementation based on winston.\n *\n * @public\n */\nexport class WinstonLogger implements RootLoggerService {\n #winston: Logger;\n #addRedactions?: (redactions: Iterable<string>) => void;\n\n /**\n * Creates a {@link WinstonLogger} instance.\n */\n static create(options: WinstonLoggerOptions): WinstonLogger {\n const redacter = WinstonLogger.redacter();\n const defaultFormatter =\n process.env.NODE_ENV === 'production'\n ? format.json()\n : WinstonLogger.colorFormat();\n\n let logger = createLogger({\n level: process.env.LOG_LEVEL || options.level || 'info',\n format: format.combine(\n options.format ?? defaultFormatter,\n redacter.format,\n ),\n transports: options.transports ?? new transports.Console(),\n });\n\n if (options.meta) {\n logger = logger.child(options.meta);\n }\n\n return new WinstonLogger(logger, redacter.add);\n }\n\n /**\n * Creates a winston log formatter for redacting secrets.\n */\n static redacter(): {\n format: Format;\n add: (redactions: Iterable<string>) => void;\n } {\n const redactionSet = new Set<string>();\n\n let redactionPattern: RegExp | undefined = undefined;\n\n return {\n format: format((obj: TransformableInfo) => {\n if (!redactionPattern || !obj) {\n return obj;\n }\n\n obj[MESSAGE] = obj[MESSAGE]?.replace?.(redactionPattern, '***');\n\n return obj;\n })(),\n add(newRedactions) {\n let added = 0;\n for (const redactionToTrim of newRedactions) {\n // Skip null or undefined values\n if (redactionToTrim === null || redactionToTrim === undefined) {\n continue;\n }\n // Trimming the string ensures that we don't accdentally get extra\n // newlines or other whitespace interfering with the redaction; this\n // can happen for example when using string literals in yaml\n const redaction = redactionToTrim.trim();\n // Exclude secrets that are empty or just one character in length. These\n // typically mean that you are running local dev or tests, or using the\n // --lax flag which sets things to just 'x'.\n if (redaction.length <= 1) {\n continue;\n }\n if (!redactionSet.has(redaction)) {\n redactionSet.add(redaction);\n added += 1;\n }\n }\n if (added > 0) {\n const redactions = Array.from(redactionSet)\n .map(r => escapeRegExp(r))\n .join('|');\n redactionPattern = new RegExp(`(${redactions})`, 'g');\n }\n },\n };\n }\n\n /**\n * Creates a pretty printed winston log formatter.\n */\n static colorFormat(): Format {\n const colorizer = format.colorize();\n\n return format.combine(\n format.timestamp(),\n format.colorize({\n colors: {\n timestamp: 'dim',\n prefix: 'blue',\n field: 'cyan',\n debug: 'grey',\n },\n }),\n format.printf((info: TransformableInfo) => {\n const { timestamp, level, message, plugin, service, ...fields } = info;\n const prefix = plugin || service;\n const timestampColor = colorizer.colorize('timestamp', timestamp);\n const prefixColor = colorizer.colorize('prefix', prefix);\n\n const extraFields = Object.entries(fields)\n .map(([key, value]) => {\n let stringValue = '';\n\n try {\n stringValue = JSON.stringify(value);\n } catch (e) {\n stringValue = '[field value not castable to string]';\n }\n\n return `${colorizer.colorize('field', `${key}`)}=${stringValue}`;\n })\n .join(' ');\n\n return `${timestampColor} ${prefixColor} ${level} ${message} ${extraFields}`;\n }),\n );\n }\n\n private constructor(\n winston: Logger,\n addRedactions?: (redactions: Iterable<string>) => void,\n ) {\n this.#winston = winston;\n this.#addRedactions = addRedactions;\n }\n\n error(message: string, meta?: JsonObject): void {\n this.#winston.error(message, meta);\n }\n\n warn(message: string, meta?: JsonObject): void {\n this.#winston.warn(message, meta);\n }\n\n info(message: string, meta?: JsonObject): void {\n this.#winston.info(message, meta);\n }\n\n debug(message: string, meta?: JsonObject): void {\n this.#winston.debug(message, meta);\n }\n\n child(meta: JsonObject): LoggerService {\n return new WinstonLogger(this.#winston.child(meta));\n }\n\n addRedactions(redactions: Iterable<string>) {\n this.#addRedactions?.(redactions);\n }\n}\n"],"names":["format","createLogger","transports","MESSAGE","escapeRegExp"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WinstonLogger.cjs.js","sources":["../../../src/entrypoints/rootLogger/WinstonLogger.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n LoggerService,\n RootLoggerService,\n} from '@backstage/backend-plugin-api';\nimport { JsonObject } from '@backstage/types';\nimport { Format, TransformableInfo } from 'logform';\nimport {\n Logger,\n format,\n createLogger,\n transports,\n transport as Transport,\n config as winstonConfig,\n} from 'winston';\nimport { MESSAGE } from 'triple-beam';\nimport { escapeRegExp } from '../../lib/escapeRegExp';\nimport { winstonLevels, WinstonLoggerLevelOverride } from './types';\nimport { createLogMatcher } from './utils';\n\n/**\n * @public\n */\nexport interface WinstonLoggerOptions {\n meta?: JsonObject;\n level?: string;\n format?: Format;\n transports?: Transport[];\n}\n\n/**\n * A {@link @backstage/backend-plugin-api#LoggerService} implementation based on winston.\n *\n * @public\n */\nexport class WinstonLogger implements RootLoggerService {\n #winston: Logger;\n #addRedactions?: (redactions: Iterable<string>) => void;\n #setLevelOverrides?: (overrides: WinstonLoggerLevelOverride[]) => void;\n\n /**\n * Creates a {@link WinstonLogger} instance.\n */\n static create(options: WinstonLoggerOptions): WinstonLogger {\n const defaultLogLevel = process.env.LOG_LEVEL || options.level || 'info';\n\n const redacter = WinstonLogger.redacter();\n const logLevelFilter = WinstonLogger.logLevelFilter(defaultLogLevel);\n\n const defaultFormatter =\n process.env.NODE_ENV === 'production'\n ? format.json()\n : WinstonLogger.colorFormat();\n\n let logger = createLogger({\n // Lowest level possible as we let the logLevelFilter do the filtering\n level: 'silly',\n format: format.combine(\n logLevelFilter.format,\n options.format ?? defaultFormatter,\n redacter.format,\n ),\n transports: options.transports ?? new transports.Console(),\n });\n\n if (options.meta) {\n logger = logger.child(options.meta);\n }\n\n return new WinstonLogger(logger, redacter.add, logLevelFilter.setOverrides);\n }\n\n /**\n * Creates a winston log formatter for redacting secrets.\n */\n static redacter(): {\n format: Format;\n add: (redactions: Iterable<string>) => void;\n } {\n const redactionSet = new Set<string>();\n\n let redactionPattern: RegExp | undefined = undefined;\n\n return {\n format: format((obj: TransformableInfo) => {\n if (!redactionPattern || !obj) {\n return obj;\n }\n\n obj[MESSAGE] = obj[MESSAGE]?.replace?.(redactionPattern, '***');\n\n return obj;\n })(),\n add(newRedactions) {\n let added = 0;\n for (const redactionToTrim of newRedactions) {\n // Skip null or undefined values\n if (redactionToTrim === null || redactionToTrim === undefined) {\n continue;\n }\n // Trimming the string ensures that we don't accdentally get extra\n // newlines or other whitespace interfering with the redaction; this\n // can happen for example when using string literals in yaml\n const redaction = redactionToTrim.trim();\n // Exclude secrets that are empty or just one character in length. These\n // typically mean that you are running local dev or tests, or using the\n // --lax flag which sets things to just 'x'.\n if (redaction.length <= 1) {\n continue;\n }\n if (!redactionSet.has(redaction)) {\n redactionSet.add(redaction);\n added += 1;\n }\n }\n if (added > 0) {\n const redactions = Array.from(redactionSet)\n .map(r => escapeRegExp(r))\n .join('|');\n redactionPattern = new RegExp(`(${redactions})`, 'g');\n }\n },\n };\n }\n\n /**\n * Creates a pretty printed winston log formatter.\n */\n static colorFormat(): Format {\n const colorizer = format.colorize();\n\n return format.combine(\n format.timestamp(),\n format.colorize({\n colors: {\n timestamp: 'dim',\n prefix: 'blue',\n field: 'cyan',\n debug: 'grey',\n },\n }),\n format.printf((info: TransformableInfo) => {\n const { timestamp, level, message, plugin, service, ...fields } = info;\n const prefix = plugin || service;\n const timestampColor = colorizer.colorize('timestamp', timestamp);\n const prefixColor = colorizer.colorize('prefix', prefix);\n\n const extraFields = Object.entries(fields)\n .map(([key, value]) => {\n let stringValue = '';\n\n try {\n stringValue = JSON.stringify(value);\n } catch (e) {\n stringValue = '[field value not castable to string]';\n }\n\n return `${colorizer.colorize('field', `${key}`)}=${stringValue}`;\n })\n .join(' ');\n\n return `${timestampColor} ${prefixColor} ${level} ${message} ${extraFields}`;\n }),\n );\n }\n\n /**\n * Formatter that filters log levels using overrides, falling back to the default level when no criteria match.\n */\n static logLevelFilter(\n defaultLogLevel: keyof winstonConfig.NpmConfigSetLevels,\n ): {\n format: Format;\n setOverrides: (overrides: WinstonLoggerLevelOverride[]) => void;\n } {\n const overrides: {\n predicate: (log: TransformableInfo) => boolean;\n level: string;\n }[] = [];\n\n return {\n format: format(log => {\n for (const override of overrides) {\n if (override.predicate(log)) {\n // Discard the log if the log level is below the override\n // eg, if the override level is 'warn' (1) and the log is 'debug' (5)\n if (winstonLevels[log.level] > winstonLevels[override.level]) {\n return false;\n }\n\n return log;\n }\n }\n\n // Ignore logs that are below the global level\n // eg, if the global level is 'warn' (1) and the log level is 'debug' (5)\n if (winstonLevels[log.level] > winstonLevels[defaultLogLevel]) {\n return false;\n }\n\n return log;\n })(),\n setOverrides: newOverrides => {\n const newOverridesPredicates = newOverrides.map(o => ({\n predicate: createLogMatcher(o.matchers),\n level: o.level,\n }));\n // Replace the content while preserving the reference to support live config updates\n overrides.splice(0, overrides.length, ...newOverridesPredicates);\n },\n };\n }\n\n private constructor(\n winston: Logger,\n addRedactions?: (redactions: Iterable<string>) => void,\n setLevelOverrides?: (overrides: WinstonLoggerLevelOverride[]) => void,\n ) {\n this.#winston = winston;\n this.#addRedactions = addRedactions;\n this.#setLevelOverrides = setLevelOverrides;\n }\n\n error(message: string, meta?: JsonObject): void {\n this.#winston.error(message, meta);\n }\n\n warn(message: string, meta?: JsonObject): void {\n this.#winston.warn(message, meta);\n }\n\n info(message: string, meta?: JsonObject): void {\n this.#winston.info(message, meta);\n }\n\n debug(message: string, meta?: JsonObject): void {\n this.#winston.debug(message, meta);\n }\n\n child(meta: JsonObject): LoggerService {\n return new WinstonLogger(this.#winston.child(meta));\n }\n\n addRedactions(redactions: Iterable<string>) {\n this.#addRedactions?.(redactions);\n }\n\n setLevelOverrides(overrides: WinstonLoggerLevelOverride[]) {\n this.#setLevelOverrides?.(overrides);\n }\n}\n"],"names":["format","createLogger","transports","MESSAGE","escapeRegExp","winstonLevels","createLogMatcher"],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var types = require('./types.cjs.js');
|
|
4
|
+
|
|
5
|
+
const getRootLoggerConfig = (config) => {
|
|
6
|
+
const level = config.getOptionalString("backend.logger.level");
|
|
7
|
+
const meta = config.getOptionalConfig("backend.logger.meta")?.get();
|
|
8
|
+
const overridesConfig = config.getOptionalConfigArray(
|
|
9
|
+
"backend.logger.overrides"
|
|
10
|
+
);
|
|
11
|
+
const overrides = overridesConfig?.map((override, i) => {
|
|
12
|
+
const overrideLevel = override.getString("level");
|
|
13
|
+
if (types.winstonLevels[overrideLevel] === void 0) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
`Invalid config at backend.logger.overrides[${i}].level, '${overrideLevel}' is not a valid logging level, must be one of 'error', 'warn', 'info' or 'debug'.`
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
const matchers = override.getConfig("matchers").get();
|
|
19
|
+
return {
|
|
20
|
+
matchers,
|
|
21
|
+
level: overrideLevel
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
return {
|
|
25
|
+
meta,
|
|
26
|
+
level,
|
|
27
|
+
overrides
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
exports.getRootLoggerConfig = getRootLoggerConfig;
|
|
32
|
+
//# sourceMappingURL=config.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.cjs.js","sources":["../../../src/entrypoints/rootLogger/config.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { RootConfigService } from '@backstage/backend-plugin-api';\nimport { JsonObject } from '@backstage/types';\nimport {\n RootLoggerConfig,\n winstonLevels,\n WinstonLoggerLevelOverrideMatchers,\n} from './types';\n\nexport const getRootLoggerConfig = (\n config: RootConfigService,\n): RootLoggerConfig => {\n const level = config.getOptionalString('backend.logger.level');\n const meta = config\n .getOptionalConfig('backend.logger.meta')\n ?.get<JsonObject>();\n\n const overridesConfig = config.getOptionalConfigArray(\n 'backend.logger.overrides',\n );\n const overrides = overridesConfig?.map((override, i) => {\n const overrideLevel = override.getString('level');\n if (winstonLevels[overrideLevel] === undefined) {\n throw new Error(\n `Invalid config at backend.logger.overrides[${i}].level, '${overrideLevel}' is not a valid logging level, must be one of 'error', 'warn', 'info' or 'debug'.`,\n );\n }\n\n const matchers = override\n .getConfig('matchers')\n .get<WinstonLoggerLevelOverrideMatchers>();\n\n return {\n matchers,\n level: overrideLevel,\n };\n });\n\n return {\n meta,\n level,\n overrides,\n };\n};\n"],"names":["winstonLevels"],"mappings":";;;;AAuBO,MAAM,mBAAA,GAAsB,CACjC,MAAA,KACqB;AACrB,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,iBAAA,CAAkB,sBAAsB,CAAA;AAC7D,EAAA,MAAM,IAAA,GAAO,MAAA,CACV,iBAAA,CAAkB,qBAAqB,GACtC,GAAA,EAAgB;AAEpB,EAAA,MAAM,kBAAkB,MAAA,CAAO,sBAAA;AAAA,IAC7B;AAAA,GACF;AACA,EAAA,MAAM,SAAA,GAAY,eAAA,EAAiB,GAAA,CAAI,CAAC,UAAU,CAAA,KAAM;AACtD,IAAA,MAAM,aAAA,GAAgB,QAAA,CAAS,SAAA,CAAU,OAAO,CAAA;AAChD,IAAA,IAAIA,mBAAA,CAAc,aAAa,CAAA,KAAM,MAAA,EAAW;AAC9C,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,2CAAA,EAA8C,CAAC,CAAA,UAAA,EAAa,aAAa,CAAA,kFAAA;AAAA,OAC3E;AAAA,IACF;AAEA,IAAA,MAAM,QAAA,GAAW,QAAA,CACd,SAAA,CAAU,UAAU,EACpB,GAAA,EAAwC;AAE3C,IAAA,OAAO;AAAA,MACL,QAAA;AAAA,MACA,KAAA,EAAO;AAAA,KACT;AAAA,EACF,CAAC,CAAA;AAED,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,KAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
|
|
@@ -2,26 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
4
|
var winston = require('winston');
|
|
5
|
-
var WinstonLogger = require('./WinstonLogger.cjs.js');
|
|
6
5
|
var createConfigSecretEnumerator = require('../rootConfig/createConfigSecretEnumerator.cjs.js');
|
|
6
|
+
var WinstonLogger = require('./WinstonLogger.cjs.js');
|
|
7
|
+
var config = require('./config.cjs.js');
|
|
7
8
|
|
|
8
9
|
const rootLoggerServiceFactory = backendPluginApi.createServiceFactory({
|
|
9
10
|
service: backendPluginApi.coreServices.rootLogger,
|
|
10
11
|
deps: {
|
|
11
12
|
config: backendPluginApi.coreServices.rootConfig
|
|
12
13
|
},
|
|
13
|
-
async factory({ config }) {
|
|
14
|
+
async factory({ config: config$1 }) {
|
|
15
|
+
const rootLoggerConfig = config.getRootLoggerConfig(config$1);
|
|
14
16
|
const logger = WinstonLogger.WinstonLogger.create({
|
|
15
17
|
meta: {
|
|
16
|
-
service: "backstage"
|
|
18
|
+
service: "backstage",
|
|
19
|
+
...rootLoggerConfig.meta
|
|
17
20
|
},
|
|
18
|
-
level: process.env.LOG_LEVEL || "info",
|
|
21
|
+
level: process.env.LOG_LEVEL || rootLoggerConfig.level || "info",
|
|
19
22
|
format: process.env.NODE_ENV === "production" ? winston.format.json() : WinstonLogger.WinstonLogger.colorFormat(),
|
|
20
23
|
transports: [new winston.transports.Console()]
|
|
21
24
|
});
|
|
22
25
|
const secretEnumerator = await createConfigSecretEnumerator.createConfigSecretEnumerator({ logger });
|
|
23
|
-
logger.addRedactions(secretEnumerator(config));
|
|
24
|
-
config.subscribe?.(() => logger.addRedactions(secretEnumerator(config)));
|
|
26
|
+
logger.addRedactions(secretEnumerator(config$1));
|
|
27
|
+
config$1.subscribe?.(() => logger.addRedactions(secretEnumerator(config$1)));
|
|
28
|
+
logger.setLevelOverrides(rootLoggerConfig.overrides ?? []);
|
|
29
|
+
config$1.subscribe?.(
|
|
30
|
+
() => logger.setLevelOverrides(config.getRootLoggerConfig(config$1).overrides ?? [])
|
|
31
|
+
);
|
|
25
32
|
return logger;
|
|
26
33
|
}
|
|
27
34
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rootLoggerServiceFactory.cjs.js","sources":["../../../src/entrypoints/rootLogger/rootLoggerServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n
|
|
1
|
+
{"version":3,"file":"rootLoggerServiceFactory.cjs.js","sources":["../../../src/entrypoints/rootLogger/rootLoggerServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { format, transports } from 'winston';\nimport { createConfigSecretEnumerator } from '../rootConfig/createConfigSecretEnumerator';\nimport { WinstonLogger } from '../rootLogger/WinstonLogger';\nimport { getRootLoggerConfig } from './config';\n\n/**\n * Root-level logging.\n *\n * See {@link @backstage/backend-plugin-api#RootLoggerService}\n * and {@link https://backstage.io/docs/backend-system/core-services/root-logger | the service docs}\n * for more information.\n *\n * @public\n */\nexport const rootLoggerServiceFactory = createServiceFactory({\n service: coreServices.rootLogger,\n deps: {\n config: coreServices.rootConfig,\n },\n async factory({ config }) {\n const rootLoggerConfig = getRootLoggerConfig(config);\n\n const logger = WinstonLogger.create({\n meta: {\n service: 'backstage',\n ...rootLoggerConfig.meta,\n },\n level: process.env.LOG_LEVEL || rootLoggerConfig.level || 'info',\n format:\n process.env.NODE_ENV === 'production'\n ? format.json()\n : WinstonLogger.colorFormat(),\n transports: [new transports.Console()],\n });\n\n const secretEnumerator = await createConfigSecretEnumerator({ logger });\n logger.addRedactions(secretEnumerator(config));\n config.subscribe?.(() => logger.addRedactions(secretEnumerator(config)));\n\n logger.setLevelOverrides(rootLoggerConfig.overrides ?? []);\n config.subscribe?.(() =>\n logger.setLevelOverrides(getRootLoggerConfig(config).overrides ?? []),\n );\n\n return logger;\n },\n});\n"],"names":["createServiceFactory","coreServices","config","getRootLoggerConfig","WinstonLogger","format","transports","createConfigSecretEnumerator"],"mappings":";;;;;;;;AAkCO,MAAM,2BAA2BA,qCAAA,CAAqB;AAAA,EAC3D,SAASC,6BAAA,CAAa,UAAA;AAAA,EACtB,IAAA,EAAM;AAAA,IACJ,QAAQA,6BAAA,CAAa;AAAA,GACvB;AAAA,EACA,MAAM,OAAA,CAAQ,UAAEC,QAAA,EAAO,EAAG;AACxB,IAAA,MAAM,gBAAA,GAAmBC,2BAAoBD,QAAM,CAAA;AAEnD,IAAA,MAAM,MAAA,GAASE,4BAAc,MAAA,CAAO;AAAA,MAClC,IAAA,EAAM;AAAA,QACJ,OAAA,EAAS,WAAA;AAAA,QACT,GAAG,gBAAA,CAAiB;AAAA,OACtB;AAAA,MACA,KAAA,EAAO,OAAA,CAAQ,GAAA,CAAI,SAAA,IAAa,iBAAiB,KAAA,IAAS,MAAA;AAAA,MAC1D,MAAA,EACE,QAAQ,GAAA,CAAI,QAAA,KAAa,eACrBC,cAAA,CAAO,IAAA,EAAK,GACZD,2BAAA,CAAc,WAAA,EAAY;AAAA,MAChC,UAAA,EAAY,CAAC,IAAIE,kBAAA,CAAW,SAAS;AAAA,KACtC,CAAA;AAED,IAAA,MAAM,gBAAA,GAAmB,MAAMC,yDAAA,CAA6B,EAAE,QAAQ,CAAA;AACtE,IAAA,MAAA,CAAO,aAAA,CAAc,gBAAA,CAAiBL,QAAM,CAAC,CAAA;AAC7C,IAAAA,QAAA,CAAO,YAAY,MAAM,MAAA,CAAO,cAAc,gBAAA,CAAiBA,QAAM,CAAC,CAAC,CAAA;AAEvE,IAAA,MAAA,CAAO,iBAAA,CAAkB,gBAAA,CAAiB,SAAA,IAAa,EAAE,CAAA;AACzD,IAAAA,QAAA,CAAO,SAAA;AAAA,MAAY,MACjB,OAAO,iBAAA,CAAkBC,0BAAA,CAAoBD,QAAM,CAAA,CAAE,SAAA,IAAa,EAAE;AAAA,KACtE;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AACF,CAAC;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.cjs.js","sources":["../../../src/entrypoints/rootLogger/types.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { JsonObject, JsonPrimitive } from '@backstage/types';\nimport { config as winstonConfig } from 'winston';\n\n/**\n * @public\n */\nexport type WinstonLoggerLevelOverrideMatchers = {\n [key: string]: JsonPrimitive | JsonPrimitive[] | undefined;\n};\n\n/**\n * @public\n */\nexport type WinstonLoggerLevelOverride = {\n matchers: WinstonLoggerLevelOverrideMatchers;\n level: string;\n};\n\nexport type RootLoggerConfig = {\n level?: string;\n meta?: JsonObject;\n overrides?: WinstonLoggerLevelOverride[];\n};\n\nexport const winstonLevels = winstonConfig.npm.levels;\n"],"names":["winstonConfig"],"mappings":";;;;AAuCO,MAAM,aAAA,GAAgBA,eAAc,GAAA,CAAI;;;;"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const parseRegex = (s) => {
|
|
4
|
+
if (!s.startsWith("/")) return null;
|
|
5
|
+
const lastSlash = s.lastIndexOf("/");
|
|
6
|
+
if (lastSlash <= 0) return null;
|
|
7
|
+
const pattern = s.slice(1, lastSlash);
|
|
8
|
+
const flags = s.slice(lastSlash + 1);
|
|
9
|
+
try {
|
|
10
|
+
return new RegExp(pattern, flags);
|
|
11
|
+
} catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const createLogFieldMatcher = (matcher) => {
|
|
16
|
+
if (Array.isArray(matcher)) {
|
|
17
|
+
const fns = matcher.map((m) => createLogFieldMatcher(m));
|
|
18
|
+
return (logField) => fns.some((fn) => fn(logField));
|
|
19
|
+
}
|
|
20
|
+
if (typeof matcher !== "string") {
|
|
21
|
+
return (logField) => logField === matcher;
|
|
22
|
+
}
|
|
23
|
+
const regex = parseRegex(matcher);
|
|
24
|
+
if (regex) {
|
|
25
|
+
return (logField) => typeof logField === "string" && regex.test(logField);
|
|
26
|
+
}
|
|
27
|
+
return (logField) => logField === matcher;
|
|
28
|
+
};
|
|
29
|
+
const createLogMatcher = (matchers) => {
|
|
30
|
+
const logFieldMatchers = Object.entries(matchers).map(([key, m]) => {
|
|
31
|
+
const fn = createLogFieldMatcher(m);
|
|
32
|
+
return [key, fn];
|
|
33
|
+
});
|
|
34
|
+
return (log) => logFieldMatchers.every(([key, fn]) => fn(log[key]));
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
exports.createLogMatcher = createLogMatcher;
|
|
38
|
+
//# sourceMappingURL=utils.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.cjs.js","sources":["../../../src/entrypoints/rootLogger/utils.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TransformableInfo } from 'logform';\nimport { WinstonLoggerLevelOverrideMatchers } from './types';\n\n/** Parse a slash-delimited regex like `/pattern/flags` into a RegExp, or null if not a regex-string */\nconst parseRegex = (s: string): RegExp | null => {\n if (!s.startsWith('/')) return null;\n const lastSlash = s.lastIndexOf('/');\n if (lastSlash <= 0) return null;\n\n const pattern = s.slice(1, lastSlash);\n const flags = s.slice(lastSlash + 1);\n\n try {\n return new RegExp(pattern, flags);\n } catch {\n return null; // fall back to treating it as a plain string\n }\n};\n\n/**\n * Create a predicate function that determines whether a log field matches a given matcher.\n *\n * The matcher can be:\n * - A string (exact match or regex pattern delimited by slashes, e.g. `/pattern/`)\n * - A non-string value (compared by strict equality)\n * - An array of matchers (returns true if any matcher matches)\n *\n * @param matcher - The matcher or array of matchers to compare against the log field.\n * @returns A function that takes a log field and returns `true` if it matches the matcher, otherwise `false`.\n */\nconst createLogFieldMatcher = (\n matcher: WinstonLoggerLevelOverrideMatchers[0],\n): ((logField: unknown) => boolean) => {\n // Array of matchers: create predicates for each element and OR them together\n if (Array.isArray(matcher)) {\n const fns = matcher.map(m => createLogFieldMatcher(m));\n return (logField: unknown) => fns.some(fn => fn(logField));\n }\n\n // Non-string matcher: strict equality\n if (typeof matcher !== 'string') {\n return (logField: unknown) => logField === matcher;\n }\n\n // String matcher: maybe a slash-delimited regex (/pattern/flags)\n const regex = parseRegex(matcher);\n if (regex) {\n return (logField: unknown) =>\n typeof logField === 'string' && regex.test(logField);\n }\n\n // Plain string matcher: strict equality\n return (logField: unknown) => logField === matcher;\n};\n\n/**\n * Create a predicate function that determines whether a log entry matches\n * all specified override matchers.\n *\n * Iterates over each key-matcher pair in the provided `matchers` object,\n * retrieves the corresponding field from the `log` object, and checks if\n * the field matches the matcher using `isLogFieldMatching`. Returns `true`\n * only if all matchers are satisfied.\n *\n * @param matchers - An object where each key corresponds to a log field and each value is a matcher to test against that field.\n * @returns A function that takes a log entry and returns `true` if it matches all specified matchers, otherwise `false`.\n */\nexport const createLogMatcher = (\n matchers: WinstonLoggerLevelOverrideMatchers,\n): ((log: TransformableInfo) => boolean) => {\n const logFieldMatchers = Object.entries(matchers).map(([key, m]) => {\n const fn = createLogFieldMatcher(m);\n return [key, fn] as const;\n });\n\n return (log: TransformableInfo) =>\n logFieldMatchers.every(([key, fn]) => fn(log[key]));\n};\n"],"names":[],"mappings":";;AAoBA,MAAM,UAAA,GAAa,CAAC,CAAA,KAA6B;AAC/C,EAAA,IAAI,CAAC,CAAA,CAAE,UAAA,CAAW,GAAG,GAAG,OAAO,IAAA;AAC/B,EAAA,MAAM,SAAA,GAAY,CAAA,CAAE,WAAA,CAAY,GAAG,CAAA;AACnC,EAAA,IAAI,SAAA,IAAa,GAAG,OAAO,IAAA;AAE3B,EAAA,MAAM,OAAA,GAAU,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,SAAS,CAAA;AACpC,EAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,KAAA,CAAM,SAAA,GAAY,CAAC,CAAA;AAEnC,EAAA,IAAI;AACF,IAAA,OAAO,IAAI,MAAA,CAAO,OAAA,EAAS,KAAK,CAAA;AAAA,EAClC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF,CAAA;AAaA,MAAM,qBAAA,GAAwB,CAC5B,OAAA,KACqC;AAErC,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,EAAG;AAC1B,IAAA,MAAM,MAAM,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAA,KAAK,qBAAA,CAAsB,CAAC,CAAC,CAAA;AACrD,IAAA,OAAO,CAAC,QAAA,KAAsB,GAAA,CAAI,KAAK,CAAA,EAAA,KAAM,EAAA,CAAG,QAAQ,CAAC,CAAA;AAAA,EAC3D;AAGA,EAAA,IAAI,OAAO,YAAY,QAAA,EAAU;AAC/B,IAAA,OAAO,CAAC,aAAsB,QAAA,KAAa,OAAA;AAAA,EAC7C;AAGA,EAAA,MAAM,KAAA,GAAQ,WAAW,OAAO,CAAA;AAChC,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,OAAO,CAAC,QAAA,KACN,OAAO,aAAa,QAAA,IAAY,KAAA,CAAM,KAAK,QAAQ,CAAA;AAAA,EACvD;AAGA,EAAA,OAAO,CAAC,aAAsB,QAAA,KAAa,OAAA;AAC7C,CAAA;AAcO,MAAM,gBAAA,GAAmB,CAC9B,QAAA,KAC0C;AAC1C,EAAA,MAAM,gBAAA,GAAmB,MAAA,CAAO,OAAA,CAAQ,QAAQ,CAAA,CAAE,IAAI,CAAC,CAAC,GAAA,EAAK,CAAC,CAAA,KAAM;AAClE,IAAA,MAAM,EAAA,GAAK,sBAAsB,CAAC,CAAA;AAClC,IAAA,OAAO,CAAC,KAAK,EAAE,CAAA;AAAA,EACjB,CAAC,CAAA;AAED,EAAA,OAAO,CAAC,GAAA,KACN,gBAAA,CAAiB,KAAA,CAAM,CAAC,CAAC,GAAA,EAAK,EAAE,CAAA,KAAM,EAAA,CAAG,GAAA,CAAI,GAAG,CAAC,CAAC,CAAA;AACtD;;;;"}
|
package/dist/package.json.cjs.js
CHANGED
package/dist/rootLogger.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
2
|
import { RootLoggerService, LoggerService } from '@backstage/backend-plugin-api';
|
|
3
|
-
import { JsonObject } from '@backstage/types';
|
|
3
|
+
import { JsonPrimitive, JsonObject } from '@backstage/types';
|
|
4
4
|
import { Format } from 'logform';
|
|
5
|
-
import { transport } from 'winston';
|
|
5
|
+
import { transport, config } from 'winston';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Root-level logging.
|
|
@@ -15,6 +15,20 @@ import { transport } from 'winston';
|
|
|
15
15
|
*/
|
|
16
16
|
declare const rootLoggerServiceFactory: _backstage_backend_plugin_api.ServiceFactory<_backstage_backend_plugin_api.RootLoggerService, "root", "singleton">;
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
type WinstonLoggerLevelOverrideMatchers = {
|
|
22
|
+
[key: string]: JsonPrimitive | JsonPrimitive[] | undefined;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
type WinstonLoggerLevelOverride = {
|
|
28
|
+
matchers: WinstonLoggerLevelOverrideMatchers;
|
|
29
|
+
level: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
18
32
|
/**
|
|
19
33
|
* @public
|
|
20
34
|
*/
|
|
@@ -46,6 +60,13 @@ declare class WinstonLogger implements RootLoggerService {
|
|
|
46
60
|
* Creates a pretty printed winston log formatter.
|
|
47
61
|
*/
|
|
48
62
|
static colorFormat(): Format;
|
|
63
|
+
/**
|
|
64
|
+
* Formatter that filters log levels using overrides, falling back to the default level when no criteria match.
|
|
65
|
+
*/
|
|
66
|
+
static logLevelFilter(defaultLogLevel: keyof config.NpmConfigSetLevels): {
|
|
67
|
+
format: Format;
|
|
68
|
+
setOverrides: (overrides: WinstonLoggerLevelOverride[]) => void;
|
|
69
|
+
};
|
|
49
70
|
private constructor();
|
|
50
71
|
error(message: string, meta?: JsonObject): void;
|
|
51
72
|
warn(message: string, meta?: JsonObject): void;
|
|
@@ -53,6 +74,7 @@ declare class WinstonLogger implements RootLoggerService {
|
|
|
53
74
|
debug(message: string, meta?: JsonObject): void;
|
|
54
75
|
child(meta: JsonObject): LoggerService;
|
|
55
76
|
addRedactions(redactions: Iterable<string>): void;
|
|
77
|
+
setLevelOverrides(overrides: WinstonLoggerLevelOverride[]): void;
|
|
56
78
|
}
|
|
57
79
|
|
|
58
|
-
export { WinstonLogger, type WinstonLoggerOptions, rootLoggerServiceFactory };
|
|
80
|
+
export { WinstonLogger, type WinstonLoggerLevelOverride, type WinstonLoggerLevelOverrideMatchers, type WinstonLoggerOptions, rootLoggerServiceFactory };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/backend-defaults",
|
|
3
|
-
"version": "0.12.1
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "Backend defaults used by Backstage backend apps",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library"
|
|
@@ -216,19 +216,19 @@
|
|
|
216
216
|
"@aws-sdk/credential-providers": "^3.350.0",
|
|
217
217
|
"@aws-sdk/types": "^3.347.0",
|
|
218
218
|
"@azure/storage-blob": "^12.5.0",
|
|
219
|
-
"@backstage/backend-app-api": "1.2.7
|
|
220
|
-
"@backstage/backend-dev-utils": "0.1.5",
|
|
221
|
-
"@backstage/backend-plugin-api": "1.4.3
|
|
222
|
-
"@backstage/cli-node": "0.2.14",
|
|
223
|
-
"@backstage/config": "1.3.3",
|
|
224
|
-
"@backstage/config-loader": "1.10.
|
|
225
|
-
"@backstage/errors": "1.2.7",
|
|
226
|
-
"@backstage/integration": "1.18.0
|
|
227
|
-
"@backstage/integration-aws-node": "0.1.17",
|
|
228
|
-
"@backstage/plugin-auth-node": "0.6.7
|
|
229
|
-
"@backstage/plugin-events-node": "0.4.15
|
|
230
|
-
"@backstage/plugin-permission-node": "0.10.4
|
|
231
|
-
"@backstage/types": "1.2.
|
|
219
|
+
"@backstage/backend-app-api": "^1.2.7",
|
|
220
|
+
"@backstage/backend-dev-utils": "^0.1.5",
|
|
221
|
+
"@backstage/backend-plugin-api": "^1.4.3",
|
|
222
|
+
"@backstage/cli-node": "^0.2.14",
|
|
223
|
+
"@backstage/config": "^1.3.3",
|
|
224
|
+
"@backstage/config-loader": "^1.10.3",
|
|
225
|
+
"@backstage/errors": "^1.2.7",
|
|
226
|
+
"@backstage/integration": "^1.18.0",
|
|
227
|
+
"@backstage/integration-aws-node": "^0.1.17",
|
|
228
|
+
"@backstage/plugin-auth-node": "^0.6.7",
|
|
229
|
+
"@backstage/plugin-events-node": "^0.4.15",
|
|
230
|
+
"@backstage/plugin-permission-node": "^0.10.4",
|
|
231
|
+
"@backstage/types": "^1.2.2",
|
|
232
232
|
"@google-cloud/storage": "^7.0.0",
|
|
233
233
|
"@keyv/memcache": "^2.0.1",
|
|
234
234
|
"@keyv/redis": "^4.0.1",
|
|
@@ -284,9 +284,9 @@
|
|
|
284
284
|
},
|
|
285
285
|
"devDependencies": {
|
|
286
286
|
"@aws-sdk/util-stream-node": "^3.350.0",
|
|
287
|
-
"@backstage/backend-plugin-api": "1.4.3
|
|
288
|
-
"@backstage/backend-test-utils": "1.9.0
|
|
289
|
-
"@backstage/cli": "0.34.2
|
|
287
|
+
"@backstage/backend-plugin-api": "^1.4.3",
|
|
288
|
+
"@backstage/backend-test-utils": "^1.9.0",
|
|
289
|
+
"@backstage/cli": "^0.34.2",
|
|
290
290
|
"@google-cloud/cloud-sql-connector": "^1.4.0",
|
|
291
291
|
"@types/archiver": "^6.0.0",
|
|
292
292
|
"@types/base64-stream": "^1.0.2",
|