├── .editorconfig ├── .eslintrc.json ├── .github ├── renovate.json └── workflows │ ├── ci.yml │ └── publish.yml ├── .gitignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── jest.config.ts ├── lerna.json ├── package.json ├── packages └── core │ ├── README.md │ ├── jest.config.ts │ ├── nest-cli.json │ ├── package.json │ ├── src │ ├── __tests__ │ │ ├── __fixtures__ │ │ │ └── .gitkeep │ │ ├── lib-usage.test.ts │ │ └── log4js.module.test.ts │ ├── index.ts │ ├── log4js.classes.ts │ ├── log4js.constants.ts │ ├── log4js.extentions.ts │ ├── log4js.module.ts │ ├── log4js.options.ts │ └── log4js.providers.ts │ ├── tsconfig.json │ └── yarn.lock ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | max_line_length = off 14 | trim_trailing_whitespace = false 15 | 16 | [*.py] 17 | indent_size = 4 18 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "sourceType": "module" 5 | }, 6 | "plugins": [ 7 | "@typescript-eslint/eslint-plugin" 8 | ], 9 | "extends": [ 10 | "plugin:@typescript-eslint/eslint-recommended", 11 | "plugin:@typescript-eslint/recommended", 12 | "prettier" 13 | ], 14 | "root": true, 15 | "env": { 16 | "node": true 17 | }, 18 | "rules": { 19 | "@typescript-eslint/interface-name-prefix": "off", 20 | "@typescript-eslint/explicit-function-return-type": "off", 21 | "@typescript-eslint/no-explicit-any": "off", 22 | "@typescript-eslint/explicit-module-boundary-types": "off", 23 | "@typescript-eslint/no-unused-vars": "off", 24 | "@typescript-eslint/ban-types": "off" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "semanticCommits": "enabled", 3 | "packageRules": [ 4 | { 5 | "updateTypes": [ 6 | "minor", 7 | "patch", 8 | "pin", 9 | "digest" 10 | ], 11 | "automerge": true 12 | }, 13 | { 14 | "depTypeList": [ 15 | "dependencies", 16 | "devDependencies" 17 | ], 18 | "automerge": true 19 | } 20 | ], 21 | "extends": [ 22 | "config:base" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | ci: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: SCM 10 | uses: actions/checkout@v2 11 | - name: Setup Node Environment 12 | uses: actions/setup-node@v1 13 | with: 14 | node-version: 14 15 | - name: Install Dependencies and Build 16 | run: | 17 | yarn 18 | yarn bootstrap 19 | yarn test:cov 20 | - name: Upload coverage to Codecov 21 | uses: codecov/codecov-action@v1 22 | with: 23 | token: ${{secrets.CODECOV_TOKEN}} 24 | file: ./reports/coverage/lcov.info 25 | flags: unittests 26 | name: codecov-umbrella 27 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | publish-npm: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: SCM 13 | uses: actions/checkout@v2 14 | - name: Setup Node Environment 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: 14 18 | - name: Install Dependencies and Build 19 | run: | 20 | yarn 21 | yarn bootstrap 22 | yarn build 23 | - name: Semantic Release 24 | run: | 25 | echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >> ~/.npmrc 26 | yarn release 27 | env: 28 | GH_TOKEN: ${{ secrets.GH_TOKEN }} 29 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 30 | NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node,code,jetbrains+all 3 | # Edit at https://www.gitignore.io/?templates=node,code,jetbrains+all 4 | 5 | ### Code ### 6 | .vscode/* 7 | !.vscode/settings.json 8 | !.vscode/tasks.json 9 | !.vscode/launch.json 10 | !.vscode/extensions.json 11 | 12 | ### JetBrains+all ### 13 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 14 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 15 | 16 | # User-specific stuff 17 | .idea/**/workspace.xml 18 | .idea/**/tasks.xml 19 | .idea/**/usage.statistics.xml 20 | .idea/**/dictionaries 21 | .idea/**/shelf 22 | 23 | # Generated files 24 | .idea/**/contentModel.xml 25 | 26 | # Sensitive or high-churn files 27 | .idea/**/dataSources/ 28 | .idea/**/dataSources.ids 29 | .idea/**/dataSources.local.xml 30 | .idea/**/sqlDataSources.xml 31 | .idea/**/dynamic.xml 32 | .idea/**/uiDesigner.xml 33 | .idea/**/dbnavigator.xml 34 | 35 | # Gradle 36 | .idea/**/gradle.xml 37 | .idea/**/libraries 38 | 39 | # Gradle and Maven with auto-import 40 | # When using Gradle or Maven with auto-import, you should exclude module files, 41 | # since they will be recreated, and may cause churn. Uncomment if using 42 | # auto-import. 43 | # .idea/modules.xml 44 | # .idea/*.iml 45 | # .idea/modules 46 | # *.iml 47 | # *.ipr 48 | 49 | # CMake 50 | cmake-build-*/ 51 | 52 | # Mongo Explorer plugin 53 | .idea/**/mongoSettings.xml 54 | 55 | # File-based project format 56 | *.iws 57 | 58 | # IntelliJ 59 | out/ 60 | 61 | # mpeltonen/sbt-idea plugin 62 | .idea_modules/ 63 | 64 | # JIRA plugin 65 | atlassian-ide-plugin.xml 66 | 67 | # Cursive Clojure plugin 68 | .idea/replstate.xml 69 | 70 | # Crashlytics plugin (for Android Studio and IntelliJ) 71 | com_crashlytics_export_strings.xml 72 | crashlytics.properties 73 | crashlytics-build.properties 74 | fabric.properties 75 | 76 | # Editor-based Rest Client 77 | .idea/httpRequests 78 | 79 | # Android studio 3.1+ serialized cache file 80 | .idea/caches/build_file_checksums.ser 81 | 82 | ### JetBrains+all Patch ### 83 | # Ignores the whole .idea folder and all .iml files 84 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 85 | 86 | .idea/ 87 | 88 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 89 | 90 | *.iml 91 | modules.xml 92 | .idea/misc.xml 93 | *.ipr 94 | 95 | # Sonarlint plugin 96 | .idea/sonarlint 97 | 98 | ### Node ### 99 | # Logs 100 | logs 101 | *.log 102 | npm-debug.log* 103 | yarn-debug.log* 104 | yarn-error.log* 105 | lerna-debug.log* 106 | 107 | # Diagnostic reports (https://nodejs.org/api/report.html) 108 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 109 | 110 | # Runtime data 111 | pids 112 | *.pid 113 | *.seed 114 | *.pid.lock 115 | 116 | # Directory for instrumented libs generated by jscoverage/JSCover 117 | lib-cov 118 | 119 | # Coverage directory used by tools like istanbul 120 | coverage 121 | *.lcov 122 | 123 | # nyc test coverage 124 | .nyc_output 125 | 126 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 127 | .grunt 128 | 129 | # Bower dependency directory (https://bower.io/) 130 | bower_components 131 | 132 | # node-waf configuration 133 | .lock-wscript 134 | 135 | # Compiled binary addons (https://nodejs.org/api/addons.html) 136 | build/Release 137 | 138 | # Dependency directories 139 | node_modules/ 140 | jspm_packages/ 141 | 142 | # TypeScript v1 declaration files 143 | typings/ 144 | 145 | # TypeScript cache 146 | *.tsbuildinfo 147 | 148 | # Optional npm cache directory 149 | .npm 150 | 151 | # Optional eslint cache 152 | .eslintcache 153 | 154 | # Optional REPL history 155 | .node_repl_history 156 | 157 | # Output of 'npm pack' 158 | *.tgz 159 | 160 | # Yarn Integrity file 161 | .yarn-integrity 162 | 163 | # dotenv environment variables file 164 | .env 165 | .env.test 166 | 167 | # parcel-bundler cache (https://parceljs.org/) 168 | .cache 169 | 170 | # next.js build output 171 | .next 172 | 173 | # nuxt.js build output 174 | .nuxt 175 | 176 | # rollup.js default build output 177 | dist/ 178 | 179 | # Uncomment the public line if your project uses Gatsby 180 | # https://nextjs.org/blog/next-9-1#public-directory-support 181 | # https://create-react-app.dev/docs/using-the-public-folder/#docsNav 182 | # public 183 | 184 | # Storybook build outputs 185 | .out 186 | .storybook-out 187 | 188 | # vuepress build output 189 | .vuepress/dist 190 | 191 | # Serverless directories 192 | .serverless/ 193 | 194 | # FuseBox cache 195 | .fusebox/ 196 | 197 | # DynamoDB Local files 198 | .dynamodb/ 199 | 200 | # Temporary folders 201 | tmp/ 202 | temp/ 203 | 204 | # End of https://www.gitignore.io/api/node,code,jetbrains+all 205 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "arrowParens": "always", 4 | "proseWrap": "never", 5 | "singleQuote": true, 6 | "trailingComma": "none", 7 | "printWidth": 120 8 | } 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.5.3](https://github.com/nest-x/nestx-log4js/compare/v1.5.2...v1.5.3) (2025-02-22) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * **deps:** update dependency rxjs to v7.8.2 ([#1315](https://github.com/nest-x/nestx-log4js/issues/1315)) ([5b8a76b](https://github.com/nest-x/nestx-log4js/commit/5b8a76b4743b5074e017cbf82504714aba69b5ff)) 7 | 8 | ## [1.5.2](https://github.com/nest-x/nestx-log4js/compare/v1.5.1...v1.5.2) (2023-03-16) 9 | 10 | 11 | ### Bug Fixes 12 | 13 | * **deps:** update dependency log4js to v6.9.1 ([875b24e](https://github.com/nest-x/nestx-log4js/commit/875b24e278f0e39bced8a17ca4677e27cb8d4913)) 14 | 15 | ## [1.5.1](https://github.com/nest-x/nestx-log4js/compare/v1.5.0...v1.5.1) (2022-01-22) 16 | 17 | 18 | ### Bug Fixes 19 | 20 | * **deps:** update dependency log4js to v6.4.0 [security] ([6b8e11c](https://github.com/nest-x/nestx-log4js/commit/6b8e11c2003e6ace33b3ffb63c08e9c8ccb95fec)) 21 | 22 | # [1.5.0](https://github.com/nest-x/nestx-log4js/compare/v1.4.0...v1.5.0) (2021-04-03) 23 | 24 | 25 | ### Features 26 | 27 | * support error trace ([#452](https://github.com/nest-x/nestx-log4js/issues/452)) ([a16cbef](https://github.com/nest-x/nestx-log4js/commit/a16cbef8db6b9cf0187dbc72eeb2d33110cc4c56)) 28 | 29 | # [1.4.0](https://github.com/nest-x/nestx-log4js/compare/v1.3.12...v1.4.0) (2021-03-31) 30 | 31 | 32 | ### Features 33 | 34 | * support error trace ([c96a22a](https://github.com/nest-x/nestx-log4js/commit/c96a22af0e77902218561f05a5d98f20e93130db)) 35 | 36 | ## [1.3.12](https://github.com/nest-x/nestx-log4js/compare/v1.3.11...v1.3.12) (2020-12-24) 37 | 38 | 39 | ### Bug Fixes 40 | 41 | * **logger:** correct method case ([a59398d](https://github.com/nest-x/nestx-log4js/commit/a59398d2526ad386e836fb6d4c961d84e8f62edc)) 42 | 43 | ## [1.3.11](https://github.com/nest-x/nestx-log4js/compare/v1.3.10...v1.3.11) (2020-12-24) 44 | 45 | 46 | ### Bug Fixes 47 | 48 | * **logger:** add static and instance method `getTimestamp` ([10b78d1](https://github.com/nest-x/nestx-log4js/commit/10b78d13bd07499635093d457e5cc772e296f0e4)) 49 | 50 | ## [1.3.10](https://github.com/nest-x/nestx-log4js/compare/v1.3.9...v1.3.10) (2020-12-24) 51 | 52 | 53 | ### Bug Fixes 54 | 55 | * **deps:** move deps to dev/peerDependencies ([49912f5](https://github.com/nest-x/nestx-log4js/commit/49912f5ce83ad45b0f6ab8a94657770e635c873e)), closes [#342](https://github.com/nest-x/nestx-log4js/issues/342) 56 | 57 | ## [1.3.9](https://github.com/nest-x/nestx-log4js/compare/v1.3.8...v1.3.9) (2020-12-21) 58 | 59 | 60 | ### Bug Fixes 61 | 62 | * **deps:** update nest monorepo to v7.6.4 ([9b1d97e](https://github.com/nest-x/nestx-log4js/commit/9b1d97e8ccaf6e0466094c25eec1bf5a91bef3d5)) 63 | 64 | ## [1.3.8](https://github.com/nest-x/nestx-log4js/compare/v1.3.7...v1.3.8) (2020-12-17) 65 | 66 | 67 | ### Bug Fixes 68 | 69 | * **deps:** update nest monorepo to v7.6.3 ([4bc27ae](https://github.com/nest-x/nestx-log4js/commit/4bc27ae9dad2b3eeef5134f0d419ddcf48f93fab)) 70 | 71 | ## [1.3.7](https://github.com/nest-x/nestx-log4js/compare/v1.3.6...v1.3.7) (2020-12-17) 72 | 73 | 74 | ### Bug Fixes 75 | 76 | * **deps:** update nest monorepo to v7.6.2 ([dbcaa0a](https://github.com/nest-x/nestx-log4js/commit/dbcaa0a7faebe08b20e71a4bcf62de79b3775016)) 77 | 78 | ## [1.3.6](https://github.com/nest-x/nestx-log4js/compare/v1.3.5...v1.3.6) (2020-12-17) 79 | 80 | 81 | ### Bug Fixes 82 | 83 | * **deps:** bump nestjs/common dependencies ([76dab38](https://github.com/nest-x/nestx-log4js/commit/76dab3890f3298587632b2c747b9f4a495cec8e8)) 84 | 85 | ## [1.3.5](https://github.com/nest-x/nestx-log4js/compare/v1.3.4...v1.3.5) (2020-12-10) 86 | 87 | 88 | ### Bug Fixes 89 | 90 | * **deps:** update nest monorepo to v7.6.1 ([5558091](https://github.com/nest-x/nestx-log4js/commit/55580912f9e5ad3f26a6b8993c74787941bcb439)) 91 | 92 | ## [1.3.4](https://github.com/nest-x/nestx-log4js/compare/v1.3.3...v1.3.4) (2020-12-10) 93 | 94 | 95 | ### Bug Fixes 96 | 97 | * **deps:** update nest monorepo to v7.6.0 ([ff12075](https://github.com/nest-x/nestx-log4js/commit/ff12075b58bcfd9fcdcc0ceafd85066a6a29172f)) 98 | 99 | ## [1.3.3](https://github.com/nest-x/nestx-log4js/compare/v1.3.2...v1.3.3) (2020-11-23) 100 | 101 | 102 | ### Bug Fixes 103 | 104 | * **deps:** update nest monorepo to v7.5.5 ([99cf84c](https://github.com/nest-x/nestx-log4js/commit/99cf84c30a73d9a873e6d878135310566bd83e36)) 105 | 106 | ## [1.3.2](https://github.com/nest-x/nestx-log4js/compare/v1.3.1...v1.3.2) (2020-11-18) 107 | 108 | 109 | ### Bug Fixes 110 | 111 | * **deps:** update nest monorepo to v7.5.4 ([464bc4c](https://github.com/nest-x/nestx-log4js/commit/464bc4caa8631831bf9dda31fcf7ebdccf0d5d0e)) 112 | 113 | ## [1.3.1](https://github.com/nest-x/nestx-log4js/compare/v1.3.0...v1.3.1) (2020-11-17) 114 | 115 | 116 | ### Bug Fixes 117 | 118 | * **deps:** update nest monorepo to v7.5.3 ([d44a50f](https://github.com/nest-x/nestx-log4js/commit/d44a50fb353576423e70a30a75d006fbdecf5f6d)) 119 | 120 | # [1.3.0](https://github.com/nest-x/nestx-log4js/compare/v1.2.1...v1.3.0) (2020-11-16) 121 | 122 | 123 | ### Features 124 | 125 | * **core:** support file depth upgrade ([#300](https://github.com/nest-x/nestx-log4js/issues/300)) ([7cfd258](https://github.com/nest-x/nestx-log4js/commit/7cfd258670da28ef7ae9d316f97a5e6bfdfccc49)) 126 | 127 | ## [1.2.1](https://github.com/nest-x/nestx-log4js/compare/v1.2.0...v1.2.1) (2020-11-14) 128 | 129 | 130 | ### Bug Fixes 131 | 132 | * add padding for default layout `LEVEL` field ([a6e57cc](https://github.com/nest-x/nestx-log4js/commit/a6e57cc8a9ebbf2748a91c0f0686bef94e69979c)) 133 | 134 | # [1.2.0](https://github.com/nest-x/nestx-log4js/compare/v1.1.4...v1.2.0) (2020-11-14) 135 | 136 | 137 | ### Features 138 | 139 | * update default layout ([a2d54df](https://github.com/nest-x/nestx-log4js/commit/a2d54dfd4bd6b554f3ecec63ab647e732b757929)) 140 | 141 | ## [1.1.4](https://github.com/nest-x/nestx-log4js/compare/v1.1.3...v1.1.4) (2020-11-13) 142 | 143 | 144 | ### Bug Fixes 145 | 146 | * **deps:** update nest monorepo to v7.5.2 ([63318d7](https://github.com/nest-x/nestx-log4js/commit/63318d7554a480692a824b8cd8b9b41ec049f904)) 147 | 148 | ## [1.1.3](https://github.com/nest-x/nestx-log4js/compare/v1.1.2...v1.1.3) (2020-11-02) 149 | 150 | 151 | ### Bug Fixes 152 | 153 | * **deps:** update nest monorepo to v7.5.1 ([91ffd0a](https://github.com/nest-x/nestx-log4js/commit/91ffd0a4104308c3d22cb822501b3c0b636b7769)) 154 | 155 | ## [1.1.2](https://github.com/nest-x/nestx-log4js/compare/v1.1.1...v1.1.2) (2020-11-02) 156 | 157 | 158 | ### Bug Fixes 159 | 160 | * **deps:** update nest monorepo to v7.5.0 ([bf537b4](https://github.com/nest-x/nestx-log4js/commit/bf537b4212f71547229af58b9a1945bc876c388c)) 161 | 162 | ## [1.1.1](https://github.com/nest-x/nestx-log4js/compare/v1.1.0...v1.1.1) (2020-10-06) 163 | 164 | 165 | ### Bug Fixes 166 | 167 | * **core:** remove new line in default pattern ([620ec02](https://github.com/nest-x/nestx-log4js/commit/620ec0282187d04ef6e6b1c3f66d4ac59591a1ad)) 168 | 169 | # [1.1.0](https://github.com/nest-x/nestx-log4js/compare/v1.0.0...v1.1.0) (2020-10-06) 170 | 171 | 172 | ### Features 173 | 174 | * **core:** update default pattern ([#255](https://github.com/nest-x/nestx-log4js/issues/255)) ([80cf7a0](https://github.com/nest-x/nestx-log4js/commit/80cf7a0cf5976ed58358fddb86e9fd8f6605653d)) 175 | 176 | # 1.0.0 (2020-10-03) 177 | 178 | 179 | ### Bug Fixes 180 | 181 | * **deps:** pin dependencies ([#1](https://github.com/nest-x/nestx-log4js/issues/1)) ([37b5018](https://github.com/nest-x/nestx-log4js/commit/37b5018384c1053a9309491475c15b253f49f04c)) 182 | * **deps:** update dependency amqplib to ^0.6.0 ([29a3ce8](https://github.com/nest-x/nestx-log4js/commit/29a3ce8a9dfef52c01e5e9318a12828302935238)) 183 | * **deps:** update dependency rxjs to v6.5.5 ([16678ca](https://github.com/nest-x/nestx-log4js/commit/16678caf62665e10575573cac0e0a926fe1d7db0)) 184 | * **deps:** update dependency rxjs to v6.6.0 ([2e4b59a](https://github.com/nest-x/nestx-log4js/commit/2e4b59a04466e4df742d8351d13b503cbef500ae)) 185 | * **deps:** update dependency rxjs to v6.6.2 ([7ed30e9](https://github.com/nest-x/nestx-log4js/commit/7ed30e9cd6cb26cb3ec2c86d74a3c27fff0683cd)) 186 | * **deps:** update dependency rxjs to v6.6.3 ([d6e7831](https://github.com/nest-x/nestx-log4js/commit/d6e7831ba791497014ebd9b73fe8f74f3736d340)) 187 | * **deps:** update nest monorepo to v6.11.11 ([#10](https://github.com/nest-x/nestx-log4js/issues/10)) ([709bac0](https://github.com/nest-x/nestx-log4js/commit/709bac0c23e295d1671af73258b52cc459d94206)) 188 | * **deps:** update nest monorepo to v6.11.9 ([#8](https://github.com/nest-x/nestx-log4js/issues/8)) ([f1e2c62](https://github.com/nest-x/nestx-log4js/commit/f1e2c6272ad5c7e1b618d7c16d40260734dc466e)) 189 | * **deps:** update nest monorepo to v7.0.10 ([ffd0bf9](https://github.com/nest-x/nestx-log4js/commit/ffd0bf9634de4b0e9f9c5f2e89b65ba197c3f74e)) 190 | * **deps:** update nest monorepo to v7.0.11 ([e5c1ff3](https://github.com/nest-x/nestx-log4js/commit/e5c1ff331e6f0f91e09aeaff80926a3405f978a7)) 191 | * **deps:** update nest monorepo to v7.0.13 ([b664499](https://github.com/nest-x/nestx-log4js/commit/b664499fcae7ca450b81e0b9bd381182f6ad35e6)) 192 | * **deps:** update nest monorepo to v7.0.2 ([#19](https://github.com/nest-x/nestx-log4js/issues/19)) ([31a8442](https://github.com/nest-x/nestx-log4js/commit/31a84422eb8a77cf4248c4018afa9d3f2a7770bd)) 193 | * **deps:** update nest monorepo to v7.0.3 ([#21](https://github.com/nest-x/nestx-log4js/issues/21)) ([68ef7af](https://github.com/nest-x/nestx-log4js/commit/68ef7af7e7859ebaccd3d5898347613aa235a74f)) 194 | * **deps:** update nest monorepo to v7.0.4 ([bdb8af7](https://github.com/nest-x/nestx-log4js/commit/bdb8af7556ac390c63a81b7e047994e79306da25)) 195 | * **deps:** update nest monorepo to v7.0.5 ([59b408d](https://github.com/nest-x/nestx-log4js/commit/59b408d4f6335ad27b4a5a78eadcc2bbde1d5eff)) 196 | * **deps:** update nest monorepo to v7.0.6 ([faa6511](https://github.com/nest-x/nestx-log4js/commit/faa6511aa04f33899034617beb78c49a7515d8ef)) 197 | * **deps:** update nest monorepo to v7.0.7 ([#46](https://github.com/nest-x/nestx-log4js/issues/46)) ([e09bd2c](https://github.com/nest-x/nestx-log4js/commit/e09bd2c750a86949a5e4d0639ea1bd1cd66245ed)) 198 | * **deps:** update nest monorepo to v7.0.8 ([7ca0c22](https://github.com/nest-x/nestx-log4js/commit/7ca0c223dfb5d6952f5d613e82e040283d5d901b)) 199 | * **deps:** update nest monorepo to v7.0.9 ([4f4b599](https://github.com/nest-x/nestx-log4js/commit/4f4b599ee710062666da094db831dfc1278393d6)) 200 | * **deps:** update nest monorepo to v7.1.0 ([835cf70](https://github.com/nest-x/nestx-log4js/commit/835cf7055aaa2fb5284478434a9db5991bd3ba37)) 201 | * **deps:** update nest monorepo to v7.1.1 ([8c8308a](https://github.com/nest-x/nestx-log4js/commit/8c8308a66edc202a9a0906ad935fa3245bdfe1c5)) 202 | * **deps:** update nest monorepo to v7.1.2 ([b270623](https://github.com/nest-x/nestx-log4js/commit/b270623cbcb90eb1135dfe3f762c0f2e26e930dc)) 203 | * **deps:** update nest monorepo to v7.1.3 ([63b8ed6](https://github.com/nest-x/nestx-log4js/commit/63b8ed6b9b7ddcf48eeef5d91aa9573f65fa0947)) 204 | * **deps:** update nest monorepo to v7.3.0 ([858424d](https://github.com/nest-x/nestx-log4js/commit/858424dae363e28975933264a64cb15340f2cfe9)) 205 | * **deps:** update nest monorepo to v7.3.1 ([e39ec76](https://github.com/nest-x/nestx-log4js/commit/e39ec76bfde4a3619adec09737570202b4ecdbab)) 206 | * **deps:** update nest monorepo to v7.3.2 ([1dd7eb2](https://github.com/nest-x/nestx-log4js/commit/1dd7eb24e254a8e8ec8d36875da497b68b797512)) 207 | * **deps:** update nest monorepo to v7.4.0 ([00329bb](https://github.com/nest-x/nestx-log4js/commit/00329bbf4b98e395476666b6d0eb32b23c98c13e)) 208 | * **deps:** update nest monorepo to v7.4.1 ([6f9e383](https://github.com/nest-x/nestx-log4js/commit/6f9e383112036880f75c1584021b94b5db98d437)) 209 | * **deps:** update nest monorepo to v7.4.2 ([3faf31a](https://github.com/nest-x/nestx-log4js/commit/3faf31a13fb1ca5c66ab14ea92a0209dfd92e2e2)) 210 | * **deps:** update nest monorepo to v7.4.3 ([99f0f45](https://github.com/nest-x/nestx-log4js/commit/99f0f45de7cd71a225d0dcdcd698c35effdaf14f)) 211 | * **deps:** update nest monorepo to v7.4.4 ([2f9b1c7](https://github.com/nest-x/nestx-log4js/commit/2f9b1c77a0b1ee3df6c3a4d824b617379e426405)) 212 | 213 | 214 | ### Features 215 | 216 | * core module setup ([#249](https://github.com/nest-x/nestx-log4js/issues/249)) ([907fe87](https://github.com/nest-x/nestx-log4js/commit/907fe8727efbc63926f6b9b6a98c157cce6c7bcb)) 217 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2020 Aquariuslt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nestx-log4js 2 | 3 | [![Github Workflow Status](https://github.com/nest-x/nestx-log4js/workflows/ci/badge.svg)](https://github.com/nest-x/nestx-log4js) 4 | [![Codecov](https://codecov.io/gh/nest-x/nestx-log4js/branch/master/graph/badge.svg)](https://codecov.io/gh/nest-x/nestx-log4js) 5 | [![Semantic-Release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) 6 | 7 | 8 | Provide log4js module as NestJS module 9 | 10 | This is root of `@nestx-log4js` monorepo. 11 | 12 | To Get Started, please read [`@nestx-log4js/core` Documentation](./packages/core/) 13 | 14 | 15 | ## Core Module Documentation 16 | 17 | `log4js` as NestJS Module. 18 | 19 |
20 | 21 | ## Features 22 | 23 | - Provide `log4js` wrapper as NestJS Global Module 24 | - Provide `Log4jsLogger` instance for replacement logger usage 25 | 26 |
27 | 28 | 29 | ## Installation 30 | 31 | ```shell 32 | yarn add @nestx-log4js/core 33 | ``` 34 | 35 |
36 | 37 | 38 | ## Usage 39 | 40 | 41 | ### Just want to use `log4js`? 42 | 43 | > Since logger is a special service in NestJS, we suppose 44 | > import `Log4jsModule` and manual call `app.useLogger(app.get(Log4jsLogger))` 45 | 46 | 47 | **app.module.ts** 48 | 49 | ```typescript 50 | import { Module } from '@nestjs/common'; 51 | import { Log4jsModule } from '@nestx-log4js/core'; 52 | 53 | 54 | @Module({ 55 | imports: [ 56 | Log4jsModule.forRoot() 57 | ] 58 | }) 59 | export class AppModule {} 60 | ``` 61 | 62 | **bootstrap.ts** 63 | 64 | ```typescript 65 | import { NestFactory } from '@nestjs/core'; 66 | import { AppModule } from './app.module'; 67 | import { Log4jsLogger } from '@nestx-log4js/core'; 68 | 69 | async function bootstrap() { 70 | const app = await NestFactory.create(AppModule); 71 | 72 | app.useLogger(app.get(Log4jsLogger)); 73 | await app.listen(3000); 74 | } 75 | bootstrap(); 76 | ``` 77 | 78 | > For more details, you can refer unit tests in source code 79 | 80 | 81 | ### Initial `Log4jsModule` with AsyncOptions (Production Usage) 82 | 83 | > You might want to use different appender (e.g. file/dateFile appender) 84 | > in real production usage and initial in your ConfigService/LoggerOnlyConfigService 85 | 86 | 87 | **app.module.ts** 88 | 89 | ```typescript 90 | import { Module } from '@nestjs/common'; 91 | import { Log4jsModule } from '@nestx-log4js/core'; 92 | 93 | // import your ConfigService/LoggerConfigService 94 | 95 | @Module({ 96 | imports: [ 97 | Log4js.forRootAsync({ 98 | inject: [ConfigService], 99 | useFactory: (config: ConfigService) => config.getLog4jsOptions() // config.getLog4jsOptions should return valid Log4jsOptions 100 | }) 101 | ] 102 | }) 103 | export class AppModule {} 104 | ``` 105 | 106 | 107 | ## Bundled Layout & Appenders 108 | 109 | When using `Log4jsModule.forRoot()` and no spec any appenders and layouts, 110 | 111 | It will use default below layouts: 112 | 113 | ```typescript 114 | export const LOG4JS_DEFAULT_LAYOUT = { 115 | type: 'pattern', 116 | // log4js default pattern %d{yyyy-MM-dd HH:mm:ss:SSS} [%thread] %-5level %logger{36} - %msg%n 117 | // we use process id instead thread id 118 | pattern: '%[%d{yyyy-MM-dd hh:mm:ss:SSS} %p --- [%15.15x{name}]%] %40.40f{3} : %m', 119 | tokens: { 120 | name: (logEvent) => { 121 | return (logEvent.context && logEvent.context['name']) || '-'; 122 | } 123 | } 124 | }; 125 | 126 | export const LOG4JS_NO_COLOUR_DEFAULT_LAYOUT = { 127 | type: 'pattern', 128 | // log4js default pattern %d{yyyy-MM-dd HH:mm:ss:SSS} [%thread] %-5level %logger{36} - %msg%n 129 | // we use process id instead thread id 130 | pattern: '%d{yyyy-MM-dd hh:mm:ss:SSS} %p --- [%15.15x{name}] %40.40f{3} : %m', 131 | tokens: { 132 | name: (logEvent) => { 133 | return (logEvent.context && logEvent.context['name']) || '-'; 134 | } 135 | } 136 | }; 137 | 138 | 139 | 140 | export const LOG4JS_DEFAULT_CONFIG: Configuration = { 141 | appenders: { 142 | stdout: { 143 | type: 'stdout', 144 | layout: LOG4JS_DEFAULT_LAYOUT 145 | }, 146 | file: { 147 | type: 'file', 148 | filename: './logs/application.log', 149 | maxLogSize: 20 * 1024 * 1024, // maxLogSize use bytes ad unit 150 | backups: 10, // default use 5 so 1KB file size total rotating 151 | layout: LOG4JS_NO_COLOUR_DEFAULT_LAYOUT 152 | } 153 | }, 154 | categories: { 155 | default: { 156 | enableCallStack: true, 157 | appenders: ['stdout', 'file'], 158 | level: 'debug' 159 | } 160 | } 161 | }; 162 | 163 | ``` 164 | 165 | It will use default below layouts (from spring boot default log pattern without process id) 166 | 167 | You can refer to [SpringBoot logging features](https://docs.spring.io/spring-boot/docs/2.1.9.RELEASE/reference/html/boot-features-logging.html) 168 | 169 | ``` 170 | 171 | 2020-11-14 15:47:24:486 INFO --- [ NestJS] core/src/log4js.classes.ts : log using nestjs as category 172 | 2020-11-14 15:47:24:486 INFO --- [ -] core/src/log4js.classes.ts : log using none as category 173 | 2020-11-14 15:47:24:490 INFO --- [ NestJS] core/src/log4js.classes.ts : log using nestjs as category 174 | 2020-11-14 15:47:24:490 WARN --- [ -] src/__tests__/log4js.module.test.ts : log using none as category 175 | 176 | ``` 177 | 178 | 179 | 180 | 181 | > Tips: You are using grok pattern via filebeat/other sidecar log agent? You can use below grok pattern: 182 | > %{TIMESTAMP_ISO8601:server_time}\s*%{LOGLEVEL:level}\s*---\s*\[\s*%{NOTSPACE:context}\]\s*%{NOTSPACE:file_path}\s*:\s*%{GREEDYDATA:content} 183 | > 184 | > It will split to friendly format (you can update alias yourself via grok document) 185 | > - server_time 186 | > - level 187 | > - context 188 | > - file_path 189 | > - content 190 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from '@jest/types'; 2 | 3 | const rootJestConfig: Config.InitialOptions = { 4 | moduleFileExtensions: [ 5 | 'ts', 6 | 'js', 7 | 'json' 8 | ], 9 | transform: { 10 | '^.+\\.(t|j)s$': 'ts-jest' 11 | }, 12 | collectCoverageFrom: [ 13 | '/src/*.ts', 14 | '!/src/__tests__/**/*.ts', 15 | '!/src/shared/**/*.ts', 16 | '!/src/index.ts', 17 | '/packages/*/src/*.ts', 18 | '!/packages/*/src/__tests__/**/*.ts', 19 | '!/packages/*/src/shared/**/*.ts', 20 | '!/packages/*/src/index.ts' 21 | ], 22 | testMatch: [ 23 | '/src/**/*.test.ts', 24 | '/packages/*/src/**/*.test.ts' 25 | ], 26 | testEnvironment: 'node', 27 | coverageDirectory: '/reports/coverage' 28 | }; 29 | 30 | export default rootJestConfig; 31 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "version": "1.5.3", 6 | "npmClient": "yarn" 7 | } 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nestx-log4js", 3 | "version": "1.5.3", 4 | "private": true, 5 | "scripts": { 6 | "bootstrap": "lerna bootstrap", 7 | "format": "prettier --write \"packages/*/src/**/*.ts\"", 8 | "lint": "eslint \"packages/*/src/**/*.ts\" --fix", 9 | "test": "jest", 10 | "test:cov": "jest --coverage", 11 | "build": "lerna run build", 12 | "release": "semantic-release" 13 | }, 14 | "dependencies": { 15 | "@nestjs/common": "8.4.7", 16 | "@nestjs/core": "9.0.5", 17 | "@nestjs/platform-express": "8.4.7", 18 | "reflect-metadata": "0.2.2", 19 | "rimraf": "5.0.10", 20 | "rxjs": "7.8.2" 21 | }, 22 | "devDependencies": { 23 | "@nestjs/cli": "9.4.2", 24 | "@nestjs/schematics": "9.0.4", 25 | "@nestjs/testing": "8.4.7", 26 | "@semantic-release/changelog": "6.0.3", 27 | "@semantic-release/exec": "6.0.3", 28 | "@semantic-release/git": "10.0.1", 29 | "@types/express": "5.0.3", 30 | "@types/jest": "27.5.2", 31 | "@types/node": "22.15.30", 32 | "@types/supertest": "6.0.3", 33 | "@typescript-eslint/eslint-plugin": "5.62.0", 34 | "@typescript-eslint/parser": "5.62.0", 35 | "eslint": "8.57.1", 36 | "eslint-config-prettier": "10.1.5", 37 | "eslint-plugin-import": "2.31.0", 38 | "eslint-plugin-prettier": "5.4.1", 39 | "jest": "26.6.3", 40 | "lerna": "6.6.2", 41 | "prettier": "3.5.3", 42 | "semantic-release": "19.0.5", 43 | "sinon": "20.0.0", 44 | "supertest": "7.1.1", 45 | "ts-jest": "26.5.6", 46 | "ts-loader": "9.5.2", 47 | "ts-node": "10.9.2", 48 | "tsconfig-paths": "4.2.0", 49 | "typescript": "5.8.3" 50 | }, 51 | "release": { 52 | "plugins": [ 53 | "@semantic-release/commit-analyzer", 54 | "@semantic-release/release-notes-generator", 55 | "@semantic-release/github", 56 | "@semantic-release/npm", 57 | "@semantic-release/changelog", 58 | [ 59 | "@semantic-release/exec", 60 | { 61 | "prepareCmd": "lerna exec --concurrency 1 -- npm version ${nextRelease.version} && lerna version ${nextRelease.version} --no-git-tag-version --no-push --amend --yes", 62 | "publishCmd": "lerna exec --concurrency 1 -- npm publish --access public --registry=https://registry.npmjs.org" 63 | } 64 | ], 65 | [ 66 | "@semantic-release/git", 67 | { 68 | "assets": [ 69 | "CHANGELOG.md", 70 | "lerna.json", 71 | "package.json", 72 | "packages/*/package.json" 73 | ], 74 | "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 75 | } 76 | ] 77 | ] 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # `@nestx-log4js/core` 2 | 3 | [![NPM](https://img.shields.io/npm/v/@nestx-log4js/core.svg)](https://www.npmjs.com/package/@nestx-log4js/core) 4 | [![Github Workflow Status](https://github.com/nest-x/nestx-log4js/workflows/ci/badge.svg)](https://github.com/nest-x/nestx-log4js) 5 | [![Codecov](https://codecov.io/gh/nest-x/nestx-log4js/branch/master/graph/badge.svg)](https://codecov.io/gh/nest-x/nestx-log4js) 6 | 7 | `log4js` as NestJS Module. 8 | 9 |
10 | 11 | ## Features 12 | 13 | - Provide `log4js` wrapper as NestJS Global Module 14 | - Provide `Log4jsLogger` instance for replacement logger usage 15 | 16 |
17 | 18 | 19 | ## Installation 20 | 21 | ```shell 22 | yarn add @nestx-log4js/core 23 | ``` 24 | 25 |
26 | 27 | 28 | ## Usage 29 | 30 | 31 | ### Just want to use `log4js`? 32 | 33 | > Since logger is a special service in NestJS, we suppose 34 | > import `Log4jsModule` and manual call `app.useLogger(app.get(Log4jsLogger))` 35 | 36 | 37 | **app.module.ts** 38 | 39 | ```typescript 40 | import { Module } from '@nestjs/common'; 41 | import { Log4jsModule } from '@nestx-log4js/core'; 42 | 43 | 44 | @Module({ 45 | imports: [ 46 | Log4jsModule.forRoot() 47 | ] 48 | }) 49 | export class AppModule {} 50 | ``` 51 | 52 | **bootstrap.ts** 53 | 54 | ```typescript 55 | import { NestFactory } from '@nestjs/core'; 56 | import { AppModule } from './app.module'; 57 | import { Log4jsLogger } from '@nestx-log4js/core'; 58 | 59 | async function bootstrap() { 60 | const app = await NestFactory.create(AppModule); 61 | 62 | app.useLogger(app.get(Log4jsLogger)); 63 | await app.listen(3000); 64 | } 65 | bootstrap(); 66 | ``` 67 | 68 | > For more details, you can refer unit tests in source code 69 | 70 | 71 | ### Initial `Log4jsModule` with AsyncOptions (Production Usage) 72 | 73 | > You might want to use different appender (e.g. file/dateFile appender) 74 | > in real production usage and initial in your ConfigService/LoggerOnlyConfigService 75 | 76 | 77 | **app.module.ts** 78 | 79 | ```typescript 80 | import { Module } from '@nestjs/common'; 81 | import { Log4jsModule } from '@nestx-log4js/core'; 82 | 83 | // import your ConfigService/LoggerConfigService 84 | 85 | @Module({ 86 | imports: [ 87 | Log4js.forRootAsync({ 88 | inject: [ConfigService], 89 | useFactory: (config: ConfigService) => config.getLog4jsOptions() // config.getLog4jsOptions should return valid Log4jsOptions 90 | }) 91 | ] 92 | }) 93 | export class AppModule {} 94 | ``` 95 | 96 | 97 | ## Bundled Layout & Appenders 98 | 99 | When using `Log4jsModule.forRoot()` and no spec any appenders and layouts, 100 | 101 | It will use default below layouts: 102 | 103 | ```typescript 104 | export const LOG4JS_DEFAULT_LAYOUT = { 105 | type: 'pattern', 106 | // log4js default pattern %d{yyyy-MM-dd HH:mm:ss:SSS} [%thread] %-5level %logger{36} - %msg%n 107 | // we use process id instead thread id 108 | pattern: '%[%d{yyyy-MM-dd hh:mm:ss:SSS} %p --- [%15.15x{name}]%] %40.40f{3} : %m', 109 | tokens: { 110 | name: (logEvent) => { 111 | return (logEvent.context && logEvent.context['name']) || '-'; 112 | } 113 | } 114 | }; 115 | 116 | export const LOG4JS_NO_COLOUR_DEFAULT_LAYOUT = { 117 | type: 'pattern', 118 | // log4js default pattern %d{yyyy-MM-dd HH:mm:ss:SSS} [%thread] %-5level %logger{36} - %msg%n 119 | // we use process id instead thread id 120 | pattern: '%d{yyyy-MM-dd hh:mm:ss:SSS} %p --- [%15.15x{name}] %40.40f{3} : %m', 121 | tokens: { 122 | name: (logEvent) => { 123 | return (logEvent.context && logEvent.context['name']) || '-'; 124 | } 125 | } 126 | }; 127 | 128 | 129 | 130 | export const LOG4JS_DEFAULT_CONFIG: Configuration = { 131 | appenders: { 132 | stdout: { 133 | type: 'stdout', 134 | layout: LOG4JS_DEFAULT_LAYOUT 135 | }, 136 | file: { 137 | type: 'file', 138 | filename: './logs/application.log', 139 | maxLogSize: 20 * 1024 * 1024, // maxLogSize use bytes ad unit 140 | backups: 10, // default use 5 so 1KB file size total rotating 141 | layout: LOG4JS_NO_COLOUR_DEFAULT_LAYOUT 142 | } 143 | }, 144 | categories: { 145 | default: { 146 | enableCallStack: true, 147 | appenders: ['stdout', 'file'], 148 | level: 'debug' 149 | } 150 | } 151 | }; 152 | 153 | ``` 154 | 155 | It will use default below layouts (from spring boot default log pattern without process id) 156 | 157 | You can refer to [SpringBoot logging features](https://docs.spring.io/spring-boot/docs/2.1.9.RELEASE/reference/html/boot-features-logging.html) 158 | 159 | ``` 160 | 161 | 2020-11-14 15:47:24:486 INFO --- [ NestJS] core/src/log4js.classes.ts : log using nestjs as category 162 | 2020-11-14 15:47:24:486 INFO --- [ -] core/src/log4js.classes.ts : log using none as category 163 | 2020-11-14 15:47:24:490 INFO --- [ NestJS] core/src/log4js.classes.ts : log using nestjs as category 164 | 2020-11-14 15:47:24:490 WARN --- [ -] src/__tests__/log4js.module.test.ts : log using none as category 165 | 166 | ``` 167 | -------------------------------------------------------------------------------- /packages/core/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from '@jest/types'; 2 | 3 | 4 | const jestConfig: Config.InitialOptions = { 5 | moduleFileExtensions: [ 6 | 'ts', 7 | 'js', 8 | 'json' 9 | ], 10 | transform: { 11 | '^.+\\.(t|j)s$': 'ts-jest' 12 | }, 13 | collectCoverageFrom: [ 14 | '/src/*.ts', 15 | '!/src/__tests__/**/*.ts', 16 | '!/src/shared/**/*.ts', 17 | '!/src/index.ts' 18 | ], 19 | testMatch: [ 20 | '/src/**/*.test.ts' 21 | ], 22 | testEnvironment: 'node', 23 | coverageDirectory: '/reports/coverage' 24 | }; 25 | 26 | 27 | export default jestConfig; 28 | -------------------------------------------------------------------------------- /packages/core/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "src" 4 | } 5 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nestx-log4js/core", 3 | "version": "1.5.3", 4 | "description": "nestx-log4js core module", 5 | "author": "aquariuslt ", 6 | "homepage": "https://github.com/nest-x/nestx-log4js#readme", 7 | "keywords": [ 8 | "nestjs", 9 | "nestx", 10 | "log4js", 11 | "logger" 12 | ], 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/nest-x/nestx-log4js.git" 16 | }, 17 | "bugs": { 18 | "url": "https://github.com/nest-x/nestx-log4js/issues" 19 | }, 20 | "license": "MIT", 21 | "publishConfig": { 22 | "access": "public" 23 | }, 24 | "files": [ 25 | "dist", 26 | "index.ts" 27 | ], 28 | "main": "dist/index.js", 29 | "scripts": { 30 | "prebuild": "rimraf dist", 31 | "build": "tsc", 32 | "test": "jest", 33 | "test:cov": "jest --coverage" 34 | }, 35 | "dependencies": { 36 | "log4js": "^6.1.2" 37 | }, 38 | "devDependencies": { 39 | "@nestjs/cli": "9.4.2", 40 | "@nestjs/common": "8.4.7", 41 | "@nestjs/core": "9.0.5", 42 | "@nestjs/schematics": "9.0.4", 43 | "@nestjs/testing": "8.4.7", 44 | "@types/jest": "27.5.2", 45 | "@types/node": "22.15.30", 46 | "jest": "26.6.3", 47 | "proxyquire": "2.1.3", 48 | "reflect-metadata": "0.2.2", 49 | "rimraf": "5.0.10", 50 | "rxjs": "7.8.2", 51 | "ts-jest": "26.5.6", 52 | "ts-loader": "9.5.2", 53 | "ts-node": "10.9.2", 54 | "tsconfig-paths": "4.2.0", 55 | "typescript": "5.8.3" 56 | }, 57 | "peerDependencies": { 58 | "@nestjs/common": "^7.0.0 || ^8.0.0", 59 | "@nestjs/core": "^7.0.0 || ^8.0.0 || ^9.0.0", 60 | "reflect-metadata": "^0.1.13 || ^0.2.0", 61 | "rxjs": "^6.5.4 || ^7.0.0" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /packages/core/src/__tests__/__fixtures__/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nest-x/nestx-log4js/4a9cc0fa7a568f3f464b76550d5bfa8a9c47feb7/packages/core/src/__tests__/__fixtures__/.gitkeep -------------------------------------------------------------------------------- /packages/core/src/__tests__/lib-usage.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @desc this is not a nest module test. 3 | * only calling log4js and complete typings 4 | **/ 5 | 6 | import * as log4js from 'log4js'; 7 | import { Configuration, LoggingEvent } from 'log4js'; 8 | 9 | describe('log4js usage', () => { 10 | afterEach(async (done) => { 11 | // waiting for log4js worker process shutdown 12 | // we should support graceful shutdown in nestjs/cloud-native project 13 | log4js.shutdown(() => { 14 | done(); 15 | }); 16 | }); 17 | 18 | it('# sample usage', () => { 19 | const logger = log4js.getLogger(); 20 | 21 | logger.level = 'debug'; 22 | logger.debug('print from default logger'); 23 | }); 24 | 25 | describe('log4js configuration', () => { 26 | it('# should load configuration via config object', () => { 27 | const config: Configuration = { 28 | appenders: { 29 | out: { 30 | type: 'file', 31 | filename: './logs/log-via-config.log' 32 | }, 33 | console: { 34 | type: 'stdout' 35 | } 36 | }, 37 | categories: { 38 | default: { 39 | appenders: ['out', 'console'], 40 | level: 'info' 41 | }, 42 | debug: { 43 | appenders: ['out', 'console'], 44 | level: 'debug' 45 | } 46 | } 47 | }; 48 | 49 | log4js.configure(config); 50 | 51 | const logger = log4js.getLogger(); 52 | logger.info('print from default logger (via configuration)'); 53 | 54 | const debugLogger = log4js.getLogger('debug'); 55 | debugLogger.debug('print from debug logger (via configuration)'); 56 | }); 57 | }); 58 | 59 | describe('log4js layout', () => { 60 | it('# should print with pattern layout', () => { 61 | const config: Configuration = { 62 | appenders: { 63 | out: { 64 | type: 'stdout', 65 | layout: { 66 | type: 'pattern', 67 | pattern: '%d %p %c %x{user} %m%n', 68 | tokens: { 69 | user: () => { 70 | return 'alice'; 71 | } 72 | } 73 | } 74 | } 75 | }, 76 | categories: { 77 | default: { 78 | appenders: ['out'], 79 | level: 'debug' 80 | } 81 | } 82 | }; 83 | 84 | log4js.configure(config); 85 | const logger = log4js.getLogger(); 86 | 87 | logger.debug('print from debug logger (via layout)'); 88 | }); 89 | 90 | it('# should print with custom layout', () => { 91 | const config: Configuration = { 92 | appenders: { 93 | out: { 94 | type: 'stdout', 95 | layout: { 96 | type: 'json' 97 | } 98 | } 99 | }, 100 | categories: { 101 | default: { 102 | appenders: ['out'], 103 | level: 'debug' 104 | } 105 | } 106 | }; 107 | 108 | log4js.addLayout('json', () => (logEvent: LoggingEvent) => { 109 | return JSON.stringify(logEvent); 110 | }); 111 | log4js.configure(config); 112 | const logger = log4js.getLogger(); 113 | 114 | logger.info('print from debug logger (via layout:json)'); 115 | }); 116 | 117 | it('# should print with custom layout + context', () => { 118 | const config: Configuration = { 119 | appenders: { 120 | out: { 121 | type: 'stdout', 122 | layout: { 123 | type: 'json-with-context' 124 | } 125 | } 126 | }, 127 | categories: { 128 | default: { 129 | appenders: ['out'], 130 | level: 'debug' 131 | } 132 | } 133 | }; 134 | 135 | log4js.addLayout('json-with-context', () => (logEvent: LoggingEvent) => { 136 | const optimizeLogEvent = { 137 | ip: logEvent.context.ip, 138 | '@timestamp': logEvent.startTime.getTime(), 139 | category: logEvent.categoryName, 140 | level: logEvent.level.levelStr, 141 | data: logEvent.data 142 | }; 143 | return JSON.stringify(optimizeLogEvent); 144 | }); 145 | log4js.configure(config); 146 | const logger = log4js.getLogger(); 147 | 148 | // most time we should add ip, env, some..other object 149 | logger.addContext('ip', '127.0.0.1'); 150 | 151 | logger.info('print from debug logger (via layout:json-with-context)'); 152 | }); 153 | }); 154 | 155 | describe('log4js file rotation', () => { 156 | it('# should enable file rotation via config', () => { 157 | const config: Configuration = { 158 | appenders: { 159 | out: { 160 | type: 'stdout' 161 | }, 162 | file: { 163 | type: 'file', 164 | filename: './logs/log-with-json-context.log', 165 | maxLogSize: 200, // maxLogSize use bytes ad unit 166 | backups: 10, // default use 5 so 1KB file size total rotating 167 | layout: { 168 | type: 'json-context' 169 | } 170 | } 171 | }, 172 | categories: { 173 | default: { 174 | appenders: ['out', 'file'], 175 | level: 'debug' 176 | } 177 | } 178 | }; 179 | 180 | log4js.addLayout('json-context', () => (logEvent: LoggingEvent) => { 181 | const optimizeLogEvent = { 182 | ip: logEvent.context.ip, 183 | '@timestamp': logEvent.startTime.getTime(), 184 | category: logEvent.categoryName, 185 | level: logEvent.level.levelStr, 186 | data: logEvent.data 187 | }; 188 | return JSON.stringify(optimizeLogEvent); 189 | }); 190 | log4js.configure(config); 191 | const logger = log4js.getLogger(); 192 | 193 | // most time we should add ip, env, some..other object 194 | logger.addContext('ip', '127.0.0.1'); 195 | 196 | logger.info('print from debug logger (via layout:json-context)'); 197 | }); 198 | }); 199 | }); 200 | -------------------------------------------------------------------------------- /packages/core/src/__tests__/log4js.module.test.ts: -------------------------------------------------------------------------------- 1 | import * as log4js from 'log4js'; 2 | import { Test, TestingModule } from '@nestjs/testing'; 3 | import { Log4jsModule } from '../log4js.module'; 4 | import { Log4jsLogger } from '../log4js.classes'; 5 | import { Logger } from '@nestjs/common'; 6 | import { LOG4JS_OPTIONS } from '../log4js.constants'; 7 | import { getLog4jsLoggerToken, getLog4jsOptionsToken } from '../log4js.options'; 8 | import { parseNestModuleCallStack } from '../log4js.extentions'; 9 | 10 | describe('@nestx-log4js module', () => { 11 | it('# should module define with sync-and-empty options correctly', async (done) => { 12 | const module: TestingModule = await Test.createTestingModule({ 13 | imports: [Log4jsModule.forRoot()] 14 | }).compile(); 15 | 16 | const app = module.createNestApplication(); 17 | await app.init(); 18 | 19 | const log4jsLogger = app.get(Log4jsLogger); 20 | expect(log4jsLogger).toBeInstanceOf(Log4jsLogger); 21 | 22 | app.useLogger(log4jsLogger); 23 | 24 | const logger = new Logger('test-log4js'); 25 | logger.log('test logger logging powered by log4js'); 26 | 27 | const log4jsModule = module.get(Log4jsModule); 28 | expect(log4jsModule).toBeInstanceOf(Log4jsModule); 29 | 30 | const log4jsOptions = app.get(LOG4JS_OPTIONS); 31 | expect(log4jsOptions).toBeDefined(); 32 | 33 | await app.close(); 34 | done(); 35 | }); 36 | 37 | it('# should module define with sync options correctly', async (done) => { 38 | const module: TestingModule = await Test.createTestingModule({ 39 | imports: [ 40 | Log4jsModule.forRoot({ 41 | config: { 42 | appenders: { 43 | out: { 44 | type: 'file', 45 | filename: './logs/log-via-config.log' 46 | }, 47 | console: { 48 | type: 'stdout' 49 | } 50 | }, 51 | categories: { 52 | default: { 53 | appenders: ['out', 'console'], 54 | level: 'info' 55 | }, 56 | debug: { 57 | appenders: ['out', 'console'], 58 | level: 'debug' 59 | } 60 | } 61 | } 62 | }) 63 | ] 64 | }).compile(); 65 | 66 | const app = module.createNestApplication(); 67 | await app.init(); 68 | 69 | const log4jsLogger = app.get(Log4jsLogger); 70 | expect(log4jsLogger).toBeInstanceOf(Log4jsLogger); 71 | 72 | app.useLogger(log4jsLogger); 73 | 74 | const logger = new Logger('test-log4js-for-root'); 75 | logger.log('test logger logging powered by log4js'); 76 | 77 | const log4jsModule = module.get(Log4jsModule); 78 | expect(log4jsModule).toBeInstanceOf(Log4jsModule); 79 | 80 | await app.close(); 81 | 82 | done(); 83 | }); 84 | 85 | it('# should module defined with async options', async (done) => { 86 | const module: TestingModule = await Test.createTestingModule({ 87 | imports: [ 88 | Log4jsModule.forRootAsync({ 89 | inject: [], 90 | useFactory: () => ({ 91 | config: { 92 | appenders: { 93 | out: { 94 | type: 'file', 95 | filename: './logs/log-via-config-async.log' 96 | }, 97 | console: { 98 | type: 'stdout' 99 | } 100 | }, 101 | categories: { 102 | default: { 103 | appenders: ['out', 'console'], 104 | level: 'info' 105 | }, 106 | debug: { 107 | appenders: ['out', 'console'], 108 | level: 'debug' 109 | } 110 | } 111 | } 112 | }) 113 | }) 114 | ] 115 | }).compile(); 116 | 117 | const app = module.createNestApplication(); 118 | await app.init(); 119 | 120 | const log4jsLogger = app.get(Log4jsLogger); 121 | expect(log4jsLogger).toBeInstanceOf(Log4jsLogger); 122 | 123 | app.useLogger(log4jsLogger); 124 | 125 | const logger = new Logger('test-log4js-for-root-async'); 126 | logger.verbose('test logger logging powered by log4js'); 127 | logger.debug('test logger logging powered by log4js'); 128 | logger.log('test logger logging powered by log4js'); 129 | logger.warn('test logger logging powered by log4js'); 130 | logger.error('test logger logging powered by log4js'); 131 | logger.error('test logger logging powered by log4js', '& error log with trace in same line'); 132 | 133 | const log4jsModule = module.get(Log4jsModule); 134 | expect(log4jsModule).toBeInstanceOf(Log4jsModule); 135 | 136 | await app.close(); 137 | 138 | done(); 139 | }); 140 | 141 | it('# should support tracestack logging', async (done) => { 142 | const module: TestingModule = await Test.createTestingModule({ 143 | imports: [ 144 | Log4jsModule.forRootAsync({ 145 | inject: [], 146 | useFactory: () => ({ 147 | config: { 148 | appenders: { 149 | out: { 150 | type: 'file', 151 | filename: './logs/log-with-error-stack.log' 152 | }, 153 | console: { 154 | type: 'stdout' 155 | } 156 | }, 157 | categories: { 158 | default: { 159 | appenders: ['out', 'console'], 160 | level: 'info' 161 | }, 162 | debug: { 163 | appenders: ['out', 'console'], 164 | level: 'debug' 165 | } 166 | } 167 | } 168 | }) 169 | }) 170 | ] 171 | }).compile(); 172 | 173 | const app = module.createNestApplication(); 174 | await app.init(); 175 | 176 | const log4jsLogger = app.get(Log4jsLogger); 177 | expect(log4jsLogger).toBeInstanceOf(Log4jsLogger); 178 | 179 | app.useLogger(log4jsLogger); 180 | 181 | const log4jsModule = module.get(Log4jsModule); 182 | expect(log4jsModule).toBeInstanceOf(Log4jsModule); 183 | 184 | 185 | const logger = new Logger('test-log4js-for-error-stack'); 186 | logger.error('will show error', (new Error).stack); 187 | 188 | await app.close(); 189 | 190 | done(); 191 | }); 192 | 193 | 194 | it('# should module defined with spec name', async (done) => { 195 | const module: TestingModule = await Test.createTestingModule({ 196 | imports: [ 197 | Log4jsModule.forRoot({ 198 | name: 'app', 199 | config: { 200 | appenders: { 201 | out: { 202 | type: 'file', 203 | filename: './logs/log-via-config.log' 204 | }, 205 | console: { 206 | type: 'stdout' 207 | } 208 | }, 209 | categories: { 210 | default: { 211 | appenders: ['out', 'console'], 212 | level: 'info' 213 | }, 214 | debug: { 215 | appenders: ['out', 'console'], 216 | level: 'debug' 217 | } 218 | } 219 | } 220 | }) 221 | ] 222 | }).compile(); 223 | 224 | const app = module.createNestApplication(); 225 | await app.init(); 226 | const log4jsLogger = app.get(Log4jsLogger); 227 | const log4jsAliasLogger = app.get(getLog4jsLoggerToken('app')); 228 | expect(log4jsLogger).toBeInstanceOf(Log4jsLogger); 229 | expect(log4jsLogger).toEqual(log4jsAliasLogger); 230 | 231 | const log4jsOptions = app.get(getLog4jsOptionsToken('app')); 232 | expect(log4jsOptions).toBeDefined(); 233 | 234 | const log4jsModule = module.get(Log4jsModule); 235 | expect(log4jsModule).toBeInstanceOf(Log4jsModule); 236 | 237 | await app.close(); 238 | 239 | done(); 240 | }); 241 | 242 | it('# should use nestjs context display as category field', async (done) => { 243 | const module: TestingModule = await Test.createTestingModule({ 244 | imports: [Log4jsModule.forRoot()] 245 | }).compile(); 246 | 247 | const app = module.createNestApplication(); 248 | await app.init(); 249 | 250 | const log4jsLogger = app.get(Log4jsLogger); 251 | expect(log4jsLogger).toBeInstanceOf(Log4jsLogger); 252 | 253 | app.useLogger(log4jsLogger); 254 | 255 | const logger = new Logger('NestJS'); 256 | logger.log('log using nestjs as category'); 257 | 258 | const unnamedLogger = new Logger(); 259 | unnamedLogger.log('log using none as category'); 260 | 261 | await app.close(); 262 | done(); 263 | }); 264 | 265 | it('# should support undefined context', async (done) => { 266 | const module: TestingModule = await Test.createTestingModule({ 267 | imports: [Log4jsModule.forRoot()] 268 | }).compile(); 269 | 270 | const app = module.createNestApplication(); 271 | await app.init(); 272 | 273 | const log4jsLogger = app.get(Log4jsLogger); 274 | expect(log4jsLogger).toBeInstanceOf(Log4jsLogger); 275 | 276 | app.useLogger(log4jsLogger); 277 | 278 | const logger = new Logger('NestJS'); 279 | logger.log('log using nestjs as category'); 280 | 281 | const unnamedLogger = log4js.getLogger(); 282 | unnamedLogger.debug('log using none as category'); 283 | 284 | await app.close(); 285 | done(); 286 | }); 287 | 288 | it('# should support file depth in callstack parsing', async (done) => { 289 | const data = { 290 | stack: 291 | 'Error: \n' + 292 | ' at Logger._log (/ci/workspace/nestx-log4js/packages/core/node_modules/log4js/lib/logger.js:88:48)\n' + 293 | ' at Logger.log (/ci/workspace/nestx-log4js/packages/core/node_modules/log4js/lib/logger.js:73:12)\n' + 294 | ' at Logger. [as info] (/ci/workspace/nestx-log4js/packages/core/node_modules/log4js/lib/logger.js:124:10)\n' + 295 | ' at Log4jsLogger.log (/ci/workspace/nestx-log4js/packages/core/src/log4js.classes.ts:34:17)\n' + 296 | ' at Logger.callFunction (/ci/workspace/nestx-log4js/packages/core/node_modules/@nestjs/common/services/logger.service.js:69:18)\n' + 297 | ' at Logger.log (/ci/workspace/nestx-log4js/packages/core/node_modules/@nestjs/common/services/logger.service.js:25:14)\n' + 298 | ' at /ci/workspace/nestx-log4js/packages/core/src/__tests__/log4js.module.test.ts:258:12\n' + 299 | ' at Generator.next ()\n' + 300 | ' at fulfilled (/ci/workspace/nestx-log4js/packages/core/src/__tests__/log4js.module.test.ts:5:58)' 301 | }; 302 | 303 | const { fileName } = parseNestModuleCallStack(data); 304 | 305 | expect(fileName).toEqual('/ci/workspace/nestx-log4js/packages/core/src/__tests__/log4js.module.test.ts'); 306 | 307 | const customStackLineResult = parseNestModuleCallStack(data, 4); 308 | 309 | expect(customStackLineResult.fileName).toEqual('/ci/workspace/nestx-log4js/packages/core/src/log4js.classes.ts'); 310 | 311 | done(); 312 | }); 313 | 314 | it('# should have `getTimestamp` function property', async (done) => { 315 | const module: TestingModule = await Test.createTestingModule({ 316 | imports: [Log4jsModule.forRoot()] 317 | }).compile(); 318 | 319 | const app = module.createNestApplication(); 320 | await app.init(); 321 | 322 | const log4jsLogger = app.get(Log4jsLogger); 323 | expect(log4jsLogger).toBeInstanceOf(Log4jsLogger); 324 | 325 | app.useLogger(log4jsLogger); 326 | 327 | expect(log4jsLogger).toHaveProperty('getTimestamp'); 328 | expect(Log4jsLogger.getTimestamp).not.toBeUndefined(); 329 | 330 | done(); 331 | }); 332 | }); 333 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './log4js.classes'; 2 | export * from './log4js.constants'; 3 | export * from './log4js.module'; 4 | export * from './log4js.options'; 5 | export * from './log4js.providers'; 6 | -------------------------------------------------------------------------------- /packages/core/src/log4js.classes.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, LoggerService } from '@nestjs/common'; 2 | import { Logger } from 'log4js'; 3 | 4 | @Injectable() 5 | export class Log4jsLogger implements LoggerService { 6 | constructor(private readonly logger: Logger) {} 7 | 8 | updateContext(context?: string) { 9 | if (context && context.length > 0) { 10 | this.logger.addContext('name', context); 11 | } else { 12 | this.logger.addContext('name', ''); 13 | } 14 | } 15 | 16 | verbose(message: any, context?: string) { 17 | this.updateContext(context); 18 | this.logger.trace(message); 19 | } 20 | 21 | debug(message: any, context?: string) { 22 | this.updateContext(context); 23 | this.logger.debug(message); 24 | } 25 | 26 | log(message: any, context?: string) { 27 | this.updateContext(context); 28 | this.logger.info(message); 29 | } 30 | 31 | warn(message: any, context?: string) { 32 | this.updateContext(context); 33 | this.logger.warn(message); 34 | } 35 | 36 | error(message: any, trace?: string, context?: string) { 37 | this.updateContext(context); 38 | this.logger.error(message, trace); 39 | } 40 | 41 | static getTimestamp() { 42 | const localeStringOptions = { 43 | year: 'numeric', 44 | hour: 'numeric', 45 | minute: 'numeric', 46 | second: 'numeric', 47 | day: '2-digit', 48 | month: '2-digit' 49 | } as const; 50 | return new Date(Date.now()).toLocaleString(undefined, localeStringOptions); 51 | } 52 | 53 | getTimestamp() { 54 | return Log4jsLogger.getTimestamp(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/core/src/log4js.constants.ts: -------------------------------------------------------------------------------- 1 | import { Configuration } from 'log4js'; 2 | 3 | export const LOG4JS_OPTIONS = Symbol('NEST_LOG4JS_OPTIONS'); 4 | export const LOG4JS_LOGGER = Symbol('NEST_LOG4JS_LOGGER'); 5 | 6 | export const LOG4JS_DEFAULT_LAYOUT = { 7 | type: 'pattern', 8 | // log4js default pattern %d{yyyy-MM-dd HH:mm:ss:SSS} [%thread] %-5level %logger{36} - %msg%n 9 | // we use process id instead thread id 10 | pattern: '%[%d{yyyy-MM-dd hh:mm:ss:SSS} %-5.5p --- [%15.15x{name}]%] %40.40f{3} : %m', 11 | tokens: { 12 | name: (logEvent) => { 13 | return (logEvent.context && logEvent.context['name']) || '-'; 14 | } 15 | } 16 | }; 17 | 18 | export const LOG4JS_NO_COLOUR_DEFAULT_LAYOUT = { 19 | type: 'pattern', 20 | // log4js default pattern %d{yyyy-MM-dd HH:mm:ss:SSS} [%thread] %-5level %logger{36} - %msg%n 21 | // we use process id instead thread id 22 | pattern: '%d{yyyy-MM-dd hh:mm:ss:SSS} %-5.5p --- [%15.15x{name}] %40.40f{3} : %m', 23 | tokens: { 24 | name: (logEvent) => { 25 | return (logEvent.context && logEvent.context['name']) || '-'; 26 | } 27 | } 28 | }; 29 | 30 | export const LOG4JS_DEFAULT_CONFIG: Configuration = { 31 | appenders: { 32 | stdout: { 33 | type: 'stdout', 34 | layout: LOG4JS_DEFAULT_LAYOUT 35 | }, 36 | file: { 37 | type: 'file', 38 | filename: './logs/application.log', 39 | maxLogSize: 20 * 1024 * 1024, // maxLogSize use bytes ad unit 40 | backups: 10, // default use 5 so 1KB file size total rotating 41 | layout: LOG4JS_NO_COLOUR_DEFAULT_LAYOUT 42 | } 43 | }, 44 | categories: { 45 | default: { 46 | enableCallStack: true, 47 | appenders: ['stdout', 'file'], 48 | level: 'debug' 49 | } 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /packages/core/src/log4js.extentions.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @desc we need upgrade skipIdx=7 so nest module wrapping log4js with 3 more call stack (after tsc) 3 | * -> log4js.classes.ts/js 4 | * -> logger.service.ts/js from @nestjs/common 5 | * -> application usage location 6 | * @see https://github.com/log4js-node/log4js-node/blob/master/lib/logger.js#L10 7 | **/ 8 | 9 | const STACK_REG = /at (?:(.+)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/; 10 | 11 | export const parseNestModuleCallStack = (data, skipIdx = 7) => { 12 | const stackLines = data.stack.split('\n').slice(skipIdx); 13 | const lineMatch = STACK_REG.exec(stackLines[0]); 14 | if (lineMatch && lineMatch.length === 6) { 15 | return { 16 | functionName: lineMatch[1], 17 | fileName: lineMatch[2], 18 | lineNumber: parseInt(lineMatch[3], 10), 19 | columnNumber: parseInt(lineMatch[4], 10), 20 | callStack: stackLines.join('\n') 21 | }; 22 | } 23 | return null; 24 | }; 25 | -------------------------------------------------------------------------------- /packages/core/src/log4js.module.ts: -------------------------------------------------------------------------------- 1 | import { DynamicModule, Global, Module } from '@nestjs/common'; 2 | import { 3 | DEFAULT_LOG4JS_OPTIONS, 4 | getLog4jsLoggerToken, 5 | getLog4jsOptionsToken, 6 | Log4jsAsyncOptions, 7 | Log4jsOptions 8 | } from './log4js.options'; 9 | import { createAsyncLog4jsOptions, createLog4jsLogger } from './log4js.providers'; 10 | import { Log4jsLogger } from './log4js.classes'; 11 | 12 | @Global() 13 | @Module({}) 14 | export class Log4jsModule { 15 | static forRoot(options: Log4jsOptions = DEFAULT_LOG4JS_OPTIONS): DynamicModule { 16 | return { 17 | module: Log4jsModule, 18 | providers: [ 19 | { 20 | provide: getLog4jsOptionsToken(options.name), 21 | useValue: options 22 | }, 23 | createLog4jsLogger(options.name), 24 | { 25 | provide: Log4jsLogger, 26 | useExisting: getLog4jsLoggerToken(options.name) 27 | } 28 | ], 29 | exports: [ 30 | getLog4jsLoggerToken(options.name), 31 | { 32 | provide: Log4jsLogger, 33 | useExisting: getLog4jsLoggerToken(options.name) 34 | } 35 | ] 36 | }; 37 | } 38 | 39 | static forRootAsync(options: Log4jsAsyncOptions): DynamicModule { 40 | return { 41 | module: Log4jsModule, 42 | imports: options.imports, 43 | providers: [ 44 | createAsyncLog4jsOptions(options), 45 | createLog4jsLogger(options.name), 46 | { 47 | provide: Log4jsLogger, 48 | useExisting: getLog4jsLoggerToken(options.name) 49 | } 50 | ], 51 | exports: [ 52 | getLog4jsLoggerToken(options.name), 53 | { 54 | provide: Log4jsLogger, 55 | useExisting: getLog4jsLoggerToken(options.name) 56 | } 57 | ] 58 | }; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /packages/core/src/log4js.options.ts: -------------------------------------------------------------------------------- 1 | import { Configuration } from 'log4js'; 2 | import { FactoryProvider, ModuleMetadata, Type } from '@nestjs/common'; 3 | import { LOG4JS_DEFAULT_CONFIG, LOG4JS_LOGGER, LOG4JS_OPTIONS } from './log4js.constants'; 4 | 5 | export interface Log4jsOptionsFactory { 6 | createLog4jsOptions(): Log4jsAsyncOptions | Promise; 7 | } 8 | 9 | export interface Log4jsOptions { 10 | name?: string; 11 | 12 | // TODO file url handling + process.env.LOG4JS_CONFIG filepath handling 13 | config?: Configuration; 14 | } 15 | 16 | /** 17 | * @see https://github.com/spring-projects/spring-boot/blob/2.3.x/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java 18 | **/ 19 | export const DEFAULT_LOG4JS_OPTIONS: Log4jsOptions = { 20 | config: LOG4JS_DEFAULT_CONFIG 21 | }; 22 | 23 | export interface Log4jsAsyncOptions extends Pick { 24 | name?: string; 25 | inject?: FactoryProvider['inject']; 26 | useExisting?: Type; 27 | useClass?: Type; 28 | useFactory?: (...args: any[]) => Log4jsOptions | Promise; 29 | } 30 | 31 | export const isSymbol = (fn: any): fn is symbol => typeof fn === 'symbol'; 32 | 33 | export const getLog4jsOptionsToken = (name: string | symbol = LOG4JS_OPTIONS): string | symbol => { 34 | if (name === LOG4JS_OPTIONS) { 35 | return LOG4JS_OPTIONS; 36 | } 37 | 38 | if (!isSymbol(name)) { 39 | return `${name}_LOG4JS_OPTIONS`; 40 | } 41 | }; 42 | 43 | export const getLog4jsLoggerToken = (name: string | symbol = LOG4JS_LOGGER): string | symbol => { 44 | if (name === LOG4JS_LOGGER) { 45 | return LOG4JS_LOGGER; 46 | } 47 | 48 | if (!isSymbol(name)) { 49 | return `${name}_LOG4JS_LOGGER`; 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /packages/core/src/log4js.providers.ts: -------------------------------------------------------------------------------- 1 | import * as log4js from 'log4js'; 2 | import { FactoryProvider } from '@nestjs/common'; 3 | import { 4 | getLog4jsLoggerToken, 5 | getLog4jsOptionsToken, 6 | Log4jsAsyncOptions, 7 | Log4jsOptions, 8 | Log4jsOptionsFactory 9 | } from './log4js.options'; 10 | import { Type } from '@nestjs/common/interfaces/type.interface'; 11 | import { Log4jsLogger } from './log4js.classes'; 12 | import { parseNestModuleCallStack } from './log4js.extentions'; 13 | 14 | export type Log4jsLoggerFactoryProvider = FactoryProvider>; 15 | export type Log4jsOptionsFactoryProvider = FactoryProvider>; 16 | 17 | export const createLog4jsLogger = (name: string): Log4jsLoggerFactoryProvider => ({ 18 | provide: getLog4jsLoggerToken(name), 19 | inject: [getLog4jsOptionsToken(name)], 20 | useFactory: async (options: Log4jsOptions): Promise => { 21 | const config = options.config; 22 | const logger = log4js.configure(config).getLogger(); 23 | 24 | logger.setParseCallStackFunction(parseNestModuleCallStack); 25 | 26 | // TODO: add log4js instance container so we can get different logger instance 27 | return new Log4jsLogger(logger); 28 | } 29 | }); 30 | 31 | export const createAsyncLog4jsOptions = (options: Log4jsAsyncOptions): Log4jsOptionsFactoryProvider => { 32 | if (options.useFactory) { 33 | return { 34 | provide: getLog4jsOptionsToken(options.name), 35 | inject: options.inject, 36 | useFactory: options.useFactory 37 | }; 38 | } 39 | 40 | const inject = [(options.useClass || options.useExisting) as Type]; 41 | 42 | return { 43 | provide: getLog4jsOptionsToken(options.name), 44 | inject: inject, 45 | useFactory: async (log4jsOptionsFactory: Log4jsOptionsFactory) => { 46 | return log4jsOptionsFactory.createLog4jsOptions(); 47 | } 48 | }; 49 | }; 50 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "declaration": true, 6 | "removeComments": true, 7 | "noLib": false, 8 | "emitDecoratorMetadata": true, 9 | "resolveJsonModule": true, 10 | "experimentalDecorators": true, 11 | "noImplicitAny": false, 12 | "sourceMap": false, 13 | "outDir": "./dist", 14 | "rootDir": "./src", 15 | "skipLibCheck": true 16 | }, 17 | "include": [ 18 | "src/**/*" 19 | ], 20 | "exclude": [ 21 | "node_modules", 22 | "src/__tests__", 23 | "**/*.spec.ts", 24 | "**/*.test.ts" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "declaration": true, 6 | "removeComments": true, 7 | "noLib": false, 8 | "emitDecoratorMetadata": true, 9 | "resolveJsonModule": true, 10 | "experimentalDecorators": true, 11 | "noImplicitAny": false, 12 | "sourceMap": false, 13 | "skipLibCheck": true 14 | }, 15 | "include": [ 16 | "src/**/*" 17 | ], 18 | "exclude": [ 19 | "node_modules", 20 | "**/*.spec.ts", 21 | "**/*.test.ts" 22 | ] 23 | } 24 | --------------------------------------------------------------------------------