diff --git a/.github/README.md b/.github/README.md deleted file mode 100644 index 8875cce..0000000 --- a/.github/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Micronaut Logging support - -Enhanced logging for Micronaut using MDC or request header. - -[![maven](https://img.shields.io/maven-central/v/io.kokuwa.micronaut/micronaut-logging.svg?label=maven)](https://central.sonatype.com/artifact/io.kokuwa.micronaut/micronaut-logging) -[![license](https://img.shields.io/badge/license-EUPL%201.2-blue)](https://git.kokuwa.io/kokuwaio/micronaut-logging/src/branch/main/LICENSE) -[![issues](https://img.shields.io/gitea/issues/open/kokuwaio/micronaut-logging?gitea_url=https%3A%2F%2Fgit.kokuwa.io)](https://git.kokuwa.io/kokuwaio/micronaut-logging/issues) -[![prs](https://img.shields.io/gitea/pull-requests/open/kokuwaio/micronaut-logging?gitea_url=https%3A%2F%2Fgit.kokuwa.io)](https://git.kokuwa.io/kokuwaio/micronaut-logging/pulls) -[![build](https://ci.kokuwa.io/api/badges/kokuwaio/micronaut-logging/status.svg)](https://ci.kokuwa.io/repos/kokuwaio/micronaut-logging/) - -For more documention see: [git.kokuwa.io/kokuwaio/micronaut-logging](https://git.kokuwa.io/kokuwaio/micronaut-logging) diff --git a/.justfile b/.justfile deleted file mode 100644 index 81f407b..0000000 --- a/.justfile +++ /dev/null @@ -1,12 +0,0 @@ -# https://just.systems/man/en/ - -[private] -@default: - just --list --unsorted - -# Run linter. -@lint: - docker run --rm --read-only --volume=$(pwd):$(pwd):ro --workdir=$(pwd) kokuwaio/yamllint - docker run --rm --read-only --volume=$(pwd):$(pwd):rw --workdir=$(pwd) kokuwaio/markdownlint --fix - docker run --rm --read-only --volume=$(pwd):$(pwd):ro --workdir=$(pwd) kokuwaio/renovate-config-validator - docker run --rm --read-only --volume=$(pwd):$(pwd):ro --workdir=$(pwd) woodpeckerci/woodpecker-cli lint diff --git a/.markdownlint.yaml b/.markdownlint.yaml deleted file mode 100644 index 5f08047..0000000 --- a/.markdownlint.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Default state for all rules -default: true - -# MD009 - Trailing spaces -MD009: - strict: true - -# MD013 - Line length -MD013: false diff --git a/.woodpecker/deploy.yaml b/.woodpecker/deploy.yaml deleted file mode 100644 index 11f903e..0000000 --- a/.woodpecker/deploy.yaml +++ /dev/null @@ -1,16 +0,0 @@ -when: - instance: ci.kokuwa.io - repo: kokuwaio/micronaut-logging - event: [manual, push] - branch: main - path: [.woodpecker/deploy.yaml, pom.xml, src/main/**] - -steps: - - maven: - image: maven:3.9.10-eclipse-temurin-17 - commands: mvn deploy --settings=.woodpecker/maven/settings.xml - environment: - MAVEN_GPG_KEY: {from_secret: woodpecker_gpg_key} - SONATYPE_ORG_USERNAME: {from_secret: sonatype_org_username} - SONATYPE_ORG_PASSWORD: {from_secret: sonatype_org_password} diff --git a/.woodpecker/lint.yaml b/.woodpecker/lint.yaml deleted file mode 100644 index 74bb114..0000000 --- a/.woodpecker/lint.yaml +++ /dev/null @@ -1,21 +0,0 @@ -when: - event: [manual, pull_request, push] - branch: main - path: [.woodpecker/lint.yaml, renovate.json, "**/*.y*ml", "**/*.md"] - -steps: - - renovate: - image: kokuwaio/renovate-config-validator - depends_on: [] - when: [path: [.woodpecker/lint.yaml, renovate.json]] - - yaml: - image: kokuwaio/yamllint - depends_on: [] - when: [path: [.woodpecker/lint.yaml, .yamllint.yaml, "**/*.y*ml"]] - - markdown: - image: kokuwaio/markdownlint - depends_on: [] - when: [path: [.woodpecker/lint.yaml, .markdownlint.yaml, "**/*.md"]] diff --git a/.woodpecker/maven/settings.xml b/.woodpecker/maven/settings.xml deleted file mode 100644 index 57ad1cb..0000000 --- a/.woodpecker/maven/settings.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - false - /woodpecker/.m2 - - - git.kokuwa.io - ${env.FORGEJO_USERNAME} - ${env.FORGEJO_PASSWORD} - - - sonatype.org - ${env.SONATYPE_ORG_USERNAME} - ${env.SONATYPE_ORG_PASSWORD} - - - - - http://mirror.woodpecker.svc.cluster.local/maven2 - central - - - diff --git a/.woodpecker/release.yaml b/.woodpecker/release.yaml deleted file mode 100644 index 21a190e..0000000 --- a/.woodpecker/release.yaml +++ /dev/null @@ -1,29 +0,0 @@ -when: - instance: ci.kokuwa.io - repo: kokuwaio/micronaut-logging - event: deployment - branch: main - -steps: - - maven: - image: maven:3.9.10-eclipse-temurin-17 - commands: - # setup git with ssk key signing - - git config user.email "$GIT_USER_EMAIL" - - git config user.name "$GIT_USER_NAME" - - git config commit.gpgsign true - - git config gpg.format ssh - - git config user.signingkey /run/secrets/sign.pub - - install -m 400 /dev/null /run/secrets/sign && echo "$GIT_SIGN_KEY" > /run/secrets/sign - - install -m 444 /dev/null /run/secrets/sign.pub && echo "$GIT_SIGN_PUB" > /run/secrets/sign.pub - # release - - mvn release:prepare release:perform --settings=.woodpecker/maven/settings.xml - environment: - MAVEN_GPG_KEY: {from_secret: woodpecker_gpg_key} - GIT_SIGN_KEY: {from_secret: woodpecker_sign_key} - GIT_SIGN_PUB: {from_secret: woodpecker_sign_pub} - FORGEJO_USERNAME: {from_secret: woodpecker_username} - FORGEJO_PASSWORD: {from_secret: woodpecker_password} - SONATYPE_ORG_USERNAME: {from_secret: sonatype_org_username} - SONATYPE_ORG_PASSWORD: {from_secret: sonatype_org_password} diff --git a/.woodpecker/verify.yaml b/.woodpecker/verify.yaml deleted file mode 100644 index 094b317..0000000 --- a/.woodpecker/verify.yaml +++ /dev/null @@ -1,9 +0,0 @@ -when: - event: [manual, pull_request] - path: [.woodpecker/verify.yaml, pom.xml, src/**] - -steps: - - test: - image: maven:3.9.10-eclipse-temurin-17 - commands: mvn verify --settings=.woodpecker/maven/settings.xml -P-deploy diff --git a/.yamllint.yaml b/.yamllint.yaml deleted file mode 100644 index 21966f2..0000000 --- a/.yamllint.yaml +++ /dev/null @@ -1,15 +0,0 @@ -extends: default - -## see https://yamllint.readthedocs.io/en/stable/rules.html -rules: - - # no need for document start - document-start: disable - - # line length is not important - line-length: disable - - # force double quotes everywhere - quoted-strings: - quote-type: double - required: only-when-needed diff --git a/LICENSE b/LICENSE index dacd3ae..261eeb9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,288 +1,201 @@ - - EUROPEAN UNION PUBLIC LICENCE v. 1.2 - EUPL © the European Union 2007, 2016 - -This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined -below) which is provided under the terms of this Licence. Any use of the Work, -other than as authorised under this Licence is prohibited (to the extent such -use is covered by a right of the copyright holder of the Work). - -The Work is provided under the terms of this Licence when the Licensor (as -defined below) has placed the following notice immediately following the -copyright notice for the Work: - - Licensed under the EUPL - -or has expressed by any other means his willingness to license under the EUPL. - -1. Definitions - -In this Licence, the following terms have the following meaning: - -- ‘The Licence’: this Licence. - -- ‘The Original Work’: the work or software distributed or communicated by the - Licensor under this Licence, available as Source Code and also as Executable - Code as the case may be. - -- ‘Derivative Works’: the works or software that could be created by the - Licensee, based upon the Original Work or modifications thereof. This Licence - does not define the extent of modification or dependence on the Original Work - required in order to classify a work as a Derivative Work; this extent is - determined by copyright law applicable in the country mentioned in Article 15. - -- ‘The Work’: the Original Work or its Derivative Works. - -- ‘The Source Code’: the human-readable form of the Work which is the most - convenient for people to study and modify. - -- ‘The Executable Code’: any code which has generally been compiled and which is - meant to be interpreted by a computer as a program. - -- ‘The Licensor’: the natural or legal person that distributes or communicates - the Work under the Licence. - -- ‘Contributor(s)’: any natural or legal person who modifies the Work under the - Licence, or otherwise contributes to the creation of a Derivative Work. - -- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of - the Work under the terms of the Licence. - -- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending, - renting, distributing, communicating, transmitting, or otherwise making - available, online or offline, copies of the Work or providing access to its - essential functionalities at the disposal of any other natural or legal - person. - -2. Scope of the rights granted by the Licence - -The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, -sublicensable licence to do the following, for the duration of copyright vested -in the Original Work: - -- use the Work in any circumstance and for all usage, -- reproduce the Work, -- modify the Work, and make Derivative Works based upon the Work, -- communicate to the public, including the right to make available or display - the Work or copies thereof to the public and perform publicly, as the case may - be, the Work, -- distribute the Work or copies thereof, -- lend and rent the Work or copies thereof, -- sublicense rights in the Work or copies thereof. - -Those rights can be exercised on any media, supports and formats, whether now -known or later invented, as far as the applicable law permits so. - -In the countries where moral rights apply, the Licensor waives his right to -exercise his moral right to the extent allowed by law in order to make effective -the licence of the economic rights here above listed. - -The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to -any patents held by the Licensor, to the extent necessary to make use of the -rights granted on the Work under this Licence. - -3. Communication of the Source Code - -The Licensor may provide the Work either in its Source Code form, or as -Executable Code. If the Work is provided as Executable Code, the Licensor -provides in addition a machine-readable copy of the Source Code of the Work -along with each copy of the Work that the Licensor distributes or indicates, in -a notice following the copyright notice attached to the Work, a repository where -the Source Code is easily and freely accessible for as long as the Licensor -continues to distribute or communicate the Work. - -4. Limitations on copyright - -Nothing in this Licence is intended to deprive the Licensee of the benefits from -any exception or limitation to the exclusive rights of the rights owners in the -Work, of the exhaustion of those rights or of other applicable limitations -thereto. - -5. Obligations of the Licensee - -The grant of the rights mentioned above is subject to some restrictions and -obligations imposed on the Licensee. Those obligations are the following: - -Attribution right: The Licensee shall keep intact all copyright, patent or -trademarks notices and all notices that refer to the Licence and to the -disclaimer of warranties. The Licensee must include a copy of such notices and a -copy of the Licence with every copy of the Work he/she distributes or -communicates. The Licensee must cause any Derivative Work to carry prominent -notices stating that the Work has been modified and the date of modification. - -Copyleft clause: If the Licensee distributes or communicates copies of the -Original Works or Derivative Works, this Distribution or Communication will be -done under the terms of this Licence or of a later version of this Licence -unless the Original Work is expressly distributed only under this version of the -Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee -(becoming Licensor) cannot offer or impose any additional terms or conditions on -the Work or Derivative Work that alter or restrict the terms of the Licence. - -Compatibility clause: If the Licensee Distributes or Communicates Derivative -Works or copies thereof based upon both the Work and another work licensed under -a Compatible Licence, this Distribution or Communication can be done under the -terms of this Compatible Licence. For the sake of this clause, ‘Compatible -Licence’ refers to the licences listed in the appendix attached to this Licence. -Should the Licensee's obligations under the Compatible Licence conflict with -his/her obligations under this Licence, the obligations of the Compatible -Licence shall prevail. - -Provision of Source Code: When distributing or communicating copies of the Work, -the Licensee will provide a machine-readable copy of the Source Code or indicate -a repository where this Source will be easily and freely available for as long -as the Licensee continues to distribute or communicate the Work. - -Legal Protection: This Licence does not grant permission to use the trade names, -trademarks, service marks, or names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the copyright notice. - -6. Chain of Authorship - -The original Licensor warrants that the copyright in the Original Work granted -hereunder is owned by him/her or licensed to him/her and that he/she has the -power and authority to grant the Licence. - -Each Contributor warrants that the copyright in the modifications he/she brings -to the Work are owned by him/her or licensed to him/her and that he/she has the -power and authority to grant the Licence. - -Each time You accept the Licence, the original Licensor and subsequent -Contributors grant You a licence to their contributions to the Work, under the -terms of this Licence. - -7. Disclaimer of Warranty - -The Work is a work in progress, which is continuously improved by numerous -Contributors. It is not a finished work and may therefore contain defects or -‘bugs’ inherent to this type of development. - -For the above reason, the Work is provided under the Licence on an ‘as is’ basis -and without warranties of any kind concerning the Work, including without -limitation merchantability, fitness for a particular purpose, absence of defects -or errors, accuracy, non-infringement of intellectual property rights other than -copyright as stated in Article 6 of this Licence. - -This disclaimer of warranty is an essential part of the Licence and a condition -for the grant of any rights to the Work. - -8. Disclaimer of Liability - -Except in the cases of wilful misconduct or damages directly caused to natural -persons, the Licensor will in no event be liable for any direct or indirect, -material or moral, damages of any kind, arising out of the Licence or of the use -of the Work, including without limitation, damages for loss of goodwill, work -stoppage, computer failure or malfunction, loss of data or any commercial -damage, even if the Licensor has been advised of the possibility of such damage. -However, the Licensor will be liable under statutory product liability laws as -far such laws apply to the Work. - -9. Additional agreements - -While distributing the Work, You may choose to conclude an additional agreement, -defining obligations or services consistent with this Licence. However, if -accepting obligations, You may act only on your own behalf and on your sole -responsibility, not on behalf of the original Licensor or any other Contributor, -and only if You agree to indemnify, defend, and hold each Contributor harmless -for any liability incurred by, or claims asserted against such Contributor by -the fact You have accepted any warranty or additional liability. - -10. Acceptance of the Licence - -The provisions of this Licence can be accepted by clicking on an icon ‘I agree’ -placed under the bottom of a window displaying the text of this Licence or by -affirming consent in any other similar way, in accordance with the rules of -applicable law. Clicking on that icon indicates your clear and irrevocable -acceptance of this Licence and all of its terms and conditions. - -Similarly, you irrevocably accept this Licence and all of its terms and -conditions by exercising any rights granted to You by Article 2 of this Licence, -such as the use of the Work, the creation by You of a Derivative Work or the -Distribution or Communication by You of the Work or copies thereof. - -11. Information to the public - -In case of any Distribution or Communication of the Work by means of electronic -communication by You (for example, by offering to download the Work from a -remote location) the distribution channel or media (for example, a website) must -at least provide to the public the information requested by the applicable law -regarding the Licensor, the Licence and the way it may be accessible, concluded, -stored and reproduced by the Licensee. - -12. Termination of the Licence - -The Licence and the rights granted hereunder will terminate automatically upon -any breach by the Licensee of the terms of the Licence. - -Such a termination will not terminate the licences of any person who has -received the Work from the Licensee under the Licence, provided such persons -remain in full compliance with the Licence. - -13. Miscellaneous - -Without prejudice of Article 9 above, the Licence represents the complete -agreement between the Parties as to the Work. - -If any provision of the Licence is invalid or unenforceable under applicable -law, this will not affect the validity or enforceability of the Licence as a -whole. Such provision will be construed or reformed so as necessary to make it -valid and enforceable. - -The European Commission may publish other linguistic versions or new versions of -this Licence or updated versions of the Appendix, so far this is required and -reasonable, without reducing the scope of the rights granted by the Licence. New -versions of the Licence will be published with a unique version number. - -All linguistic versions of this Licence, approved by the European Commission, -have identical value. Parties can take advantage of the linguistic version of -their choice. - -14. Jurisdiction - -Without prejudice to specific agreement between parties, - -- any litigation resulting from the interpretation of this License, arising - between the European Union institutions, bodies, offices or agencies, as a - Licensor, and any Licensee, will be subject to the jurisdiction of the Court - of Justice of the European Union, as laid down in article 272 of the Treaty on - the Functioning of the European Union, - -- any litigation arising between other parties and resulting from the - interpretation of this License, will be subject to the exclusive jurisdiction - of the competent court where the Licensor resides or conducts its primary - business. - -15. Applicable Law - -Without prejudice to specific agreement between parties, - -- this Licence shall be governed by the law of the European Union Member State - where the Licensor has his seat, resides or has his registered office, - -- this licence shall be governed by Belgian law if the Licensor has no seat, - residence or registered office inside a European Union Member State. - -Appendix - -‘Compatible Licences’ according to Article 5 EUPL are: - -- GNU General Public License (GPL) v. 2, v. 3 -- GNU Affero General Public License (AGPL) v. 3 -- Open Software License (OSL) v. 2.1, v. 3.0 -- Eclipse Public License (EPL) v. 1.0 -- CeCILL v. 2.0, v. 2.1 -- Mozilla Public Licence (MPL) v. 2 -- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 -- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for - works other than software -- European Union Public Licence (EUPL) v. 1.1, v. 1.2 -- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong - Reciprocity (LiLiQ-R+). - -The European Commission may update this Appendix to later versions of the above -licences without producing a new version of the EUPL, as long as they provide -the rights granted in Article 2 of this Licence and protect the covered Source -Code from exclusive appropriation. - -All other changes or additions to this Appendix require the production of a new -EUPL version. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 4a3a2ec..c62e597 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,142 @@ # Micronaut Logging support -Enhanced logging for Micronaut using MDC or request header. - -[![maven](https://img.shields.io/maven-central/v/io.kokuwa.micronaut/micronaut-logging.svg?label=maven)](https://central.sonatype.com/artifact/io.kokuwa.micronaut/micronaut-logging) -[![license](https://img.shields.io/badge/license-EUPL%201.2-blue)](https://git.kokuwa.io/kokuwaio/micronaut-logging/src/branch/main/LICENSE) -[![issues](https://img.shields.io/gitea/issues/open/kokuwaio/micronaut-logging?gitea_url=https%3A%2F%2Fgit.kokuwa.io)](https://git.kokuwa.io/kokuwaio/micronaut-logging/issues) -[![prs](https://img.shields.io/gitea/pull-requests/open/kokuwaio/micronaut-logging?gitea_url=https%3A%2F%2Fgit.kokuwa.io)](https://git.kokuwa.io/kokuwaio/micronaut-logging/pulls) -[![build](https://ci.kokuwa.io/api/badges/kokuwaio/micronaut-logging/status.svg)](https://ci.kokuwa.io/repos/kokuwaio/micronaut-logging/) - -Include in your `pom.xml`: - -```xml - - io.kokuwa.micronaut - micronaut-logging - ${version.io.kokuwa.micronaut.logging} - runtime - - - - io.micronaut.serde - micronaut-serde-jsonp - runtime - -``` - ## Features -* Version [3.x](https://github.com/kokuwaio/micronaut-logging/tree/3.x) is based on SLF4J 1.7 & Logback 1.2 & Micronaut 3.x -* Version [4.x](https://github.com/kokuwaio/micronaut-logging/tree/main) is based on SLF4J 2.0 & Logback 1.4 & Micronaut 4.x -* [set log level based on MDC values](docs/features/logback_mdc_level.md) -* [add default xml](docs/features/logback_default.md) -* [preconfigured appender for different environments](docs/features/logback_appender.md) -* [set log level based on HTTP request header](docs/features/http_log_level.md) -* [add HTTP path parts to MDC](docs/features/http_mdc_path.md) -* [add HTTP header to MDC](docs/features/http_mdc_header.md) -* [add authentication information from HTTP request to MDC](docs/features/http_mdc_authentication.md) +### Preconfigured Appender + +Buildin appender: + * console format + * Stackdriver format (with support for error reporting) + +### Set log level based on MDC values + +Configuration: + * *enabled*: enable MDC filter (`true` is default) + * *key*: MDC key, is optional (will use name instead, see example `user` below) + * *level*: log level to use (`TRACE` is default) + * *loggers*: passlist of logger names, matches all loggers if empty + * *values*: values for matching MDC key, matches all values if empty + +Example for setting different values for different values/logger: +``` +logger: + levels: + io.kokuwa: INFO + mdc: + gateway-debug: + key: gateway + level: DEBUG + loggers: + - io.kokuwa + values: + - 6a1bae7f-eb6c-4c81-af9d-dc15396584e2 + - fb3318f1-2c73-48e9-acd4-a2be3c9f9256 + gateway-trace: + key: gateway + level: TRACE + loggers: + - io.kokuwa + - io.micronaut + values: + - 257802b2-22fe-4dcc-bb99-c1db2a47861f +``` + +Example for omiting level and key: +``` +logger: + levels: + io.kokuwa: INFO + mdc: + gateway: + loggers: + - io.kokuwa + values: + - 257802b2-22fe-4dcc-bb99-c1db2a47861f + - 0a44738b-0c3a-4798-8210-2495485f10b2 +``` + +Example for minimal configuration: +``` +logger: + levels: + io.kokuwa: INFO + mdc: + user: {} +``` + +### Set log level based on HTTP request header + +Configuration for server filter (prefixed with *logger.request.filter*): + * *enabled*: enable HTTP server filter (`true` is default) + * *order*: order for [Ordered](https://github.com/micronaut-projects/micronaut-core/blob/master/core/src/main/java/io/micronaut/core/order/Ordered.java) (highest is default) + * *path*: filter path (`/**` is default) + * *header*: name of HTTP header (`x-log-level` is default) + +Configuration for client filter for propagation (prefixed with *logger.request.propagation*): + * *enabled*: enable HTTP client filter (`true` is default) + * *order*: order for [Ordered](https://github.com/micronaut-projects/micronaut-core/blob/master/core/src/main/java/io/micronaut/core/order/Ordered.java) (tracing is default) + * *path*: filter path (`/**` is default) + * *header*: name of HTTP header (server header is default) + +Example with default configuration: +``` +logger: + request: + filter: + enabled: true + order: -2147483648 + path: /** + header: x-log-level + propagation: + enabled: true + order: 19000 + path: /** + header: ${logger.request.header.header-name} +``` + +### Add princial for request to MDC + +Confguration: + * *enabled*: enable HTTP principal filter (`true` is default) + * *order*: order for [Ordered](https://github.com/micronaut-projects/micronaut-core/blob/master/core/src/main/java/io/micronaut/core/order/Ordered.java) ([ServerFilterPhase.SECURITY.after()](https://github.com/micronaut-projects/micronaut-core/blob/v2.0.1/http/src/main/java/io/micronaut/http/filter/ServerFilterPhase.java#L54) is default) + * *path*: filter path (`/**` is default) + * *key*: name of MDC header (`principal` is default) + +Example with default configuration: +``` +logger: + request: + principal: + enabled: true + order: 39250 + path: /** + key: principal +``` + +## Build & Release + +### Dependency updates + +Display dependency updates: +``` +mvn versions:display-property-updates -U +``` + +Update dependencies: +``` +mvn versions:update-properties +``` + +### Release locally + +Run: +``` +mvn release:prepare release:perform release:clean -B +``` ## Open Topics -* configure mdc on refresh event -* read **serviceName** and **serviceVersion** from yaml -* support auto select appender with custom `logback.xml` + * configure mdc on refresh event + * add stackdriver per configuration + * add fluent per configuration + * read **serviceName** and **serviceVersion** from yaml diff --git a/docs/features/http_log_level.md b/docs/features/http_log_level.md deleted file mode 100644 index 59b960d..0000000 --- a/docs/features/http_log_level.md +++ /dev/null @@ -1,35 +0,0 @@ -# Set log level based on HTTP request header - -With this features it is possible to set the log level while processing a request by adding the http header `x-log-level` with value `TRACE`. This log level is propagated to HTTP client requests. - -## Properties - -Property | Description | Default --------- | ----------- | ------- -`logger.http.level.enabled` | filter enabled? | `true` -`logger.http.level.path` | filter path | `/**` -`logger.http.level.order` | order for [Ordered](https://github.com/micronaut-projects/micronaut-core/blob/v3.2.0/core/src/main/java/io/micronaut/core/order/Ordered.java) | [ServerFilterPhase.FIRST.before()](https://github.com/micronaut-projects/micronaut-core/blob/v3.2.0/http/src/main/java/io/micronaut/http/filter/ServerFilterPhase.java#L34) -`logger.http.level.header` | name of HTTP header | `x-log-level` -`logger.http.level.propagation.enabled` | propagation enabled? | `true` -`logger.http.level.propagation.path` | propagation path | `/**` -`logger.http.level.propagation.order` | order for [Ordered](https://github.com/micronaut-projects/micronaut-core/blob/v3.2.0/core/src/main/java/io/micronaut/core/order/Ordered.java) | [Order.HIGHEST_PRECEDENCE](https://github.com/micronaut-projects/micronaut-core/blob/v3.2.0/core/src/main/java/io/micronaut/core/order/Ordered.java#L30) -`logger.http.level.propagation.header` | name of HTTP header | see `logger.http.level.header` - -## Examples - -Default configuration: - -```yaml -logger: - http: - level: - enabled: true - order: -1000 - path: /** - header: x-log-level - propagation: - enabled: true - order: 2147483648 - path: /** - header: ${logger.http.level.header} -``` diff --git a/docs/features/http_mdc_authentication.md b/docs/features/http_mdc_authentication.md deleted file mode 100644 index ff4c4e9..0000000 --- a/docs/features/http_mdc_authentication.md +++ /dev/null @@ -1,29 +0,0 @@ -# Add authentication information to MDC - -This only applies to HTTP requests with successful security authentication. - -## Properties - -Property | Description | Default --------- | ----------- | ------- -`logger.http.authentication.enabled` | filter enabled? | `true` -`logger.http.authentication.path` | filter path | `/**` -`logger.http.authentication.order` | order for [Ordered](https://github.com/micronaut-projects/micronaut-core/blob/v3.2.0/core/src/main/java/io/micronaut/core/order/Ordered.java) | [ServerFilterPhase.SECURITY.after()](https://github.com/micronaut-projects/micronaut-core/blob/v3.2.0/http/src/main/java/io/micronaut/http/filter/ServerFilterPhase.java#L54) -`logger.http.authentication.prefix` | prefix to MDC key | `` -`logger.http.authentication.name` | MDC key of authentication name | `principal` -`logger.http.authentication.attributes` | authentication attributes to add to MDC, | `[]` - -## Examples - -Configuration for adding some jwt claims: - -```yaml -logger: - http: - authentication: - prefix: jwt. - name: sub - attributes: - - aud - - azp -``` diff --git a/docs/features/http_mdc_header.md b/docs/features/http_mdc_header.md deleted file mode 100644 index 8a8e9d4..0000000 --- a/docs/features/http_mdc_header.md +++ /dev/null @@ -1,28 +0,0 @@ -# Add HTTP headers to MDC - -## Properties - -Property | Description | Default --------- | ----------- | ------- -`logger.http.header.enabled` | filter enabled? | `true` -`logger.http.header.path` | filter path | `/**` -`logger.http.header.order` | order for [Ordered](https://github.com/micronaut-projects/micronaut-core/blob/v3.2.0/core/src/main/java/io/micronaut/core/order/Ordered.java) | [ServerFilterPhase.FIRST.before()](https://github.com/micronaut-projects/micronaut-core/blob/v3.2.0/http/src/main/java/io/micronaut/http/filter/ServerFilterPhase.java#L34) -`logger.http.header.prefix` | prefix to MDC key | `` -`logger.http.header.names` | http header names to add to MDC | `[]` - -## Examples - -Configuration for b3-propagation: - -```yaml -logger: - http: - header: - prefix: header. - names: - - x-request-id - - x-b3-traceId - - x-b3-parentspanid - - x-b3-spanid - - x-b3-sampled -``` diff --git a/docs/features/http_mdc_path.md b/docs/features/http_mdc_path.md deleted file mode 100644 index b5f9f73..0000000 --- a/docs/features/http_mdc_path.md +++ /dev/null @@ -1,25 +0,0 @@ -# Add HTTP path parts to MDC - -## Properties - -Property | Description | Default --------- | ----------- | ------- -`logger.http.path.enabled` | filter enabled? | `true` -`logger.http.path.path` | filter path | `/**` -`logger.http.path.order` | order for [Ordered](https://github.com/micronaut-projects/micronaut-core/blob/v3.2.0/core/src/main/java/io/micronaut/core/order/Ordered.java) | [ServerFilterPhase.FIRST.before()](https://github.com/micronaut-projects/micronaut-core/blob/v3.2.0/http/src/main/java/io/micronaut/http/filter/ServerFilterPhase.java#L34) -`logger.http.path.prefix` | prefix to MDC key | `` -`logger.http.path.patterns` | patterns with groups to add to MDC | `[]` - -## Examples - -Configuration for adding ids: - -```yaml -logger: - http: - path: - prefix: path. - patterns: - - \/gateway\/(?[a-f0-9\-]{36}) - - \/gateway\/(?[a-f0-9\-]{36})\/configuration\/(?[a-z]+) -``` diff --git a/docs/features/logback_appender.md b/docs/features/logback_appender.md deleted file mode 100644 index d71885b..0000000 --- a/docs/features/logback_appender.md +++ /dev/null @@ -1,14 +0,0 @@ -# Appender - -## Available Appender - -* console with jansi for developers -* gcp logging format (with support for error reporting) -* json - -## AutoSelect appender - -1. if `LOGBACK_APPENDER` is set this appender will be used -2. if GCP is detected gcp appender will be used -3. if Kubernetes is detected json appender will be used -4. console appender else diff --git a/docs/features/logback_default.md b/docs/features/logback_default.md deleted file mode 100644 index 5b34f1a..0000000 --- a/docs/features/logback_default.md +++ /dev/null @@ -1,16 +0,0 @@ -# Add default logback.xml - -If no `logback.xml` by user is provided a default [logback.xml](../../src/main/resources/io/kokuwa/logback/logback-default.xml) is loaded. Otherwise use custom [logback.xml](../../src/main/resources/io/kokuwa/logback/logback-example.xml): - -```xml - - - - - - - - - - -``` diff --git a/docs/features/logback_mdc_level.md b/docs/features/logback_mdc_level.md deleted file mode 100644 index ee1e853..0000000 --- a/docs/features/logback_mdc_level.md +++ /dev/null @@ -1,66 +0,0 @@ -# Set log level based on MDC values - -This can be used to change the log level based on MDC valus. E.g. change log levels for specific users/services etc. - -## Properties - -Property | Description | Default --------- | ----------- | ------- -`logger.mdc.enabled` | MDC enabled? | `true` -`logger.mdc.` | MDC key to use | `` -`logger.mdc..key` | MDC key override, see complex example below for usage | `` -`logger.mdc..level` | log level to use | `TRACE` -`logger.mdc..loggers` | passlist of logger names, matches all loggers if empty | `[]` -`logger.mdc..values` | values for matching MDC key, matches all values if empty | `[]` - -## Examples - -Minimal configuration that logs everything with `TRACE` if MDC `principal` is present: - -```yaml -logger: - levels: - io.kokuwa: INFO - mdc: - principal: {} -``` - -Configuration that logs everything with `TRACE` for logger `io.kokuwa` if MDC `gateway` matches one value: - -```yaml -logger: - levels: - io.kokuwa: INFO - mdc: - gateway: - loggers: - - io.kokuwa - values: - - 257802b2-22fe-4dcc-bb99-c1db2a47861f - - 0a44738b-0c3a-4798-8210-2495485f10b2 -``` - -Complex example with setting different values for different values/logger: - -```yaml -logger: - levels: - io.kokuwa: INFO - mdc: - gateway-debug: - key: gateway - level: DEBUG - loggers: - - io.kokuwa - values: - - 6a1bae7f-eb6c-4c81-af9d-dc15396584e2 - - fb3318f1-2c73-48e9-acd4-a2be3c9f9256 - gateway-trace: - key: gateway - level: TRACE - loggers: - - io.kokuwa - - io.micronaut - values: - - 257802b2-22fe-4dcc-bb99-c1db2a47861f -``` diff --git a/pom.xml b/pom.xml index 22f50e6..f2ca01d 100644 --- a/pom.xml +++ b/pom.xml @@ -1,73 +1,80 @@ - + 4.0.0 + + io.kokuwa + maven-parent + 0.1.0 + + + io.kokuwa.micronaut micronaut-logging - 5.0.1-SNAPSHOT + 0.0.3 - Logging Support for Micronaut - Enhanced logging using MDC or request header. - https://git.kokuwa.io/kokuwaio/micronaut-logging + Micronaut Logging Support + TODO + https://github.com/kokuwaio/micronaut-logging 2020 - - Kokuwa.io - http://kokuwa.io - - EUPL-1.2 - https://eupl.eu/1.2/en - repo + Apache License 2.0 + https://www.apache.org/licenses/LICENSE-2.0 - - - stephan.schnabel - Stephan Schnabel - https://schnabel.org - stephan@schnabel.org - Europe/Berlin - - - - https://git.kokuwa.io/kokuwaio/micronaut-logging - scm:git:https://git.kokuwa.io/kokuwaio/micronaut-logging.git - scm:git:https://git.kokuwa.io/kokuwaio/micronaut-logging.git - HEAD + https://github.com/kokuwaio/micronaut-logging + scm:git:https://github.com/kokuwaio/micronaut-logging.git + scm:git:https://github.com/kokuwaio/micronaut-logging.git + 0.0.3 - forgejo - https://git.kokuwa.io/kokuwaio/micronaut-logging/issues + github + https://github.com/kokuwaio/micronaut-logging/issues - - woodpecker - https://ci.kokuwa.io/repos/kokuwaio/micronaut-logging - - - - sonatype.org - https://central.sonatype.com/repository/maven-snapshots/ - - - 2025-06-27T18:11:48Z - UTF-8 - 17 + + + + + + 0.1.5 + 2.0.2 + + + - io.micronaut.platform - micronaut-platform - 4.9.0 + io.micronaut + micronaut-bom + ${version.io.micronaut} pom import + + + + ch.qos.logback.contrib + logback-json-classic + ${version.ch.qos.logback.contrib} + + + ch.qos.logback.contrib + logback-json-core + ${version.ch.qos.logback.contrib} + + + ch.qos.logback.contrib + logback-jackson + ${version.ch.qos.logback.contrib} + + @@ -75,18 +82,9 @@ io.micronaut - micronaut-http + micronaut-runtime provided - - io.micronaut.security - micronaut-security - provided - - - io.micronaut.serde - micronaut-serde-api - io.micronaut.test micronaut-test-junit5 @@ -107,360 +105,52 @@ micronaut-security-jwt test - - io.micronaut.serde - micronaut-serde-jackson - test - - - org.yaml - snakeyaml - test - - - - com.fasterxml.jackson.core - jackson-databind - - - - - org.slf4j - slf4j-api - + ch.qos.logback logback-classic - ch.qos.logback - logback-core + ch.qos.logback.contrib + logback-jackson + + + ch.qos.logback.contrib + logback-json-classic - verify - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.14.0 - - class - true - true - true - -Xlint:all,-processing - - - io.micronaut - micronaut-inject-java - - - - - - org.apache.maven.plugins - maven-deploy-plugin - 3.1.4 - - - org.apache.maven.plugins - maven-gpg-plugin - 3.2.7 - - - org.apache.maven.plugins - maven-install-plugin - 3.1.4 - - - org.apache.maven.plugins - maven-invoker-plugin - 3.9.1 - - - org.apache.maven.plugins - maven-jar-plugin - 3.4.2 - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.11.2 - - - org.apache.maven.plugins - maven-release-plugin - 3.1.1 - - verify - check - deploy - deploy,release - true - @{prefix} prepare release @{releaseLabel} [CI SKIP] - @{project.version} - - - - org.apache.maven.plugins - maven-resources-plugin - 3.3.1 - - ISO-8859-1 - - - - org.apache.maven.plugins - maven-source-plugin - 3.3.1 - - - org.apache.maven.plugins - maven-surefire-plugin - 3.5.3 - - - org.codehaus.mojo - tidy-maven-plugin - 1.4.0 - - - org.sonatype.central - central-publishing-maven-plugin - 0.8.0 - - - net.revelc.code.formatter - formatter-maven-plugin - 2.27.0 - - ${project.basedir}/src/eclipse/formatter.xml - - - - net.revelc.code - impsort-maven-plugin - 1.12.0 - - true - java.,javax.,jakarta.,org. - - - - + + + src/test/resources + true + + - + org.apache.maven.plugins - maven-invoker-plugin - - - - install - integration-test - verify - - - ${project.build.directory}/its - true - test - false - true - - - - - - - - org.apache.maven.plugins - maven-install-plugin - - - default-install - - - + maven-compiler-plugin + + + + org.projectlombok + lombok + ${version.org.projectlombok} + + + io.micronaut + micronaut-inject-java + ${version.io.micronaut} + + + - - - - dev - - - !env.CI - - - - true - - - - - org.codehaus.mojo - tidy-maven-plugin - - - validate - - pom - - - - - - net.revelc.code - impsort-maven-plugin - - - validate - - sort - - - - - - net.revelc.code.formatter - formatter-maven-plugin - - - validate - - format - - - - - - - - - check - - - env.CI - - - - - - org.codehaus.mojo - tidy-maven-plugin - - - validate - - check - - - - - - net.revelc.code - impsort-maven-plugin - - - validate - - check - - - - - - net.revelc.code.formatter - formatter-maven-plugin - - - validate - - validate - - - - - - - - - deploy - - - env.CI - - - - - - - - org.apache.maven.plugins - maven-source-plugin - - - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - - - jar - - - - - - - - org.apache.maven.plugins - maven-gpg-plugin - - - - sign - - - bc - - - - - - - - - - release - - - - org.sonatype.central - central-publishing-maven-plugin - true - - sonatype.org - true - published - - - - - - diff --git a/renovate.json b/renovate.json deleted file mode 100644 index 4bf0e44..0000000 --- a/renovate.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": ["local>kokuwaio/renovate-config", ":reviewer(stephan.schnabel)"], - "packageRules": [{ - "matchPackageNames": ["io.kokuwa.micronaut:mirconaut-logging-it"], - "enabled": false - }] -} diff --git a/src/eclipse/formatter.xml b/src/eclipse/formatter.xml deleted file mode 100644 index 61186a2..0000000 --- a/src/eclipse/formatter.xml +++ /dev/null @@ -1,404 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/it/invoker.properties b/src/it/invoker.properties deleted file mode 100644 index 7920ff9..0000000 --- a/src/it/invoker.properties +++ /dev/null @@ -1,3 +0,0 @@ -invoker.environmentVariables.KUBERNETES_SERVICE_HOST= -invoker.environmentVariables.LOGBACK_APPENDER= -invoker.environmentVariables.GOOGLE_CLOUD_PROJECT= diff --git a/src/it/level-from-micronaut/invoker.properties b/src/it/level-from-micronaut/invoker.properties deleted file mode 100644 index 46bbf8c..0000000 --- a/src/it/level-from-micronaut/invoker.properties +++ /dev/null @@ -1 +0,0 @@ -invoker.environmentVariables.LOGGER_LEVELS_IO_KOKUWA_MICRONAUT_LOGGING=DEBUG diff --git a/src/it/level-from-micronaut/pom.xml b/src/it/level-from-micronaut/pom.xml deleted file mode 100644 index cf36117..0000000 --- a/src/it/level-from-micronaut/pom.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - 4.0.0 - - - io.kokuwa.micronaut - mirconaut-logging-it - LOCAL-SNAPSHOT - - - mirconaut-logging-it-level-from-micronaut - diff --git a/src/it/level-from-micronaut/postbuild.bsh b/src/it/level-from-micronaut/postbuild.bsh deleted file mode 100644 index 026881f..0000000 --- a/src/it/level-from-micronaut/postbuild.bsh +++ /dev/null @@ -1,22 +0,0 @@ -// verify log - -String expected = "^[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{0,3} main DEBUG i.k.m.logging.LoggingTest test-output-marker$"; -String[] logs = org.codehaus.plexus.util.FileUtils.fileRead(basedir + "/build.log").split("\n"); - -for (String log : logs) { - if (!log.contains("test-output-marker")) { - continue; - } - if (java.util.regex.Pattern.matches(expected, log.replaceAll("\u001B\\[[;\\d]*m", ""))) { - return true; - } else { - System.out.println("marker found, but formatting invalid:"); - System.out.println("[EXPECTED] " + expected); - System.out.println("[ACTUAL] " + log); - System.out.println("[BASE64] " + Base64.getEncoder().encodeToString(log.getBytes())); - return false; - } -} - -System.out.println("marker not found"); -return false; diff --git a/src/it/log-gcp-from-env/invoker.properties b/src/it/log-gcp-from-env/invoker.properties deleted file mode 100644 index f9f63a8..0000000 --- a/src/it/log-gcp-from-env/invoker.properties +++ /dev/null @@ -1 +0,0 @@ -invoker.environmentVariables.LOGBACK_APPENDER=GCP diff --git a/src/it/log-gcp-from-env/pom.xml b/src/it/log-gcp-from-env/pom.xml deleted file mode 100644 index 11f4a92..0000000 --- a/src/it/log-gcp-from-env/pom.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 4.0.0 - - - io.kokuwa.micronaut - mirconaut-logging-it - LOCAL-SNAPSHOT - - - mirconaut-logging-it-log-gcp-from-env - - - - io.micronaut.serde - micronaut-serde-jsonp - - - diff --git a/src/it/log-gcp-from-env/postbuild.bsh b/src/it/log-gcp-from-env/postbuild.bsh deleted file mode 100644 index d9e0657..0000000 --- a/src/it/log-gcp-from-env/postbuild.bsh +++ /dev/null @@ -1,21 +0,0 @@ -// verify log - -String expected = "^\\{\"time\":\"202[3-9]-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{0,3}Z\",\"severity\":\"INFO\",\"thread\":\"main\",\"logger\":\"io.kokuwa.micronaut.logging.LoggingTest\",\"message\":\"test-output-marker\",\"raw-message\":\"test-output-marker\"}$"; -String[] logs = org.codehaus.plexus.util.FileUtils.fileRead(basedir + "/build.log").split("\n"); - -for (String log : logs) { - if (!log.contains("test-output-marker")) { - continue; - } - if (java.util.regex.Pattern.matches(expected, log)) { - return true; - } else { - System.out.println("marker found, but formatting invalid:"); - System.out.println("[EXPECTED] " + expected); - System.out.println("[ACTUAL] " + log); - return false; - } -} - -System.out.println("marker not found"); -return false; diff --git a/src/it/log-gcp-from-gcloud/invoker.properties b/src/it/log-gcp-from-gcloud/invoker.properties deleted file mode 100644 index ec347b6..0000000 --- a/src/it/log-gcp-from-gcloud/invoker.properties +++ /dev/null @@ -1 +0,0 @@ -invoker.environmentVariables.GOOGLE_CLOUD_PROJECT=value diff --git a/src/it/log-gcp-from-gcloud/pom.xml b/src/it/log-gcp-from-gcloud/pom.xml deleted file mode 100644 index 0bf33a2..0000000 --- a/src/it/log-gcp-from-gcloud/pom.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 4.0.0 - - - io.kokuwa.micronaut - mirconaut-logging-it - LOCAL-SNAPSHOT - - - mirconaut-logging-it-log-gcp-from-gcloud - - - - io.micronaut.serde - micronaut-serde-jsonp - - - diff --git a/src/it/log-gcp-from-gcloud/postbuild.bsh b/src/it/log-gcp-from-gcloud/postbuild.bsh deleted file mode 100644 index d9e0657..0000000 --- a/src/it/log-gcp-from-gcloud/postbuild.bsh +++ /dev/null @@ -1,21 +0,0 @@ -// verify log - -String expected = "^\\{\"time\":\"202[3-9]-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{0,3}Z\",\"severity\":\"INFO\",\"thread\":\"main\",\"logger\":\"io.kokuwa.micronaut.logging.LoggingTest\",\"message\":\"test-output-marker\",\"raw-message\":\"test-output-marker\"}$"; -String[] logs = org.codehaus.plexus.util.FileUtils.fileRead(basedir + "/build.log").split("\n"); - -for (String log : logs) { - if (!log.contains("test-output-marker")) { - continue; - } - if (java.util.regex.Pattern.matches(expected, log)) { - return true; - } else { - System.out.println("marker found, but formatting invalid:"); - System.out.println("[EXPECTED] " + expected); - System.out.println("[ACTUAL] " + log); - return false; - } -} - -System.out.println("marker not found"); -return false; diff --git a/src/it/log-gcp-with-service/invoker.properties b/src/it/log-gcp-with-service/invoker.properties deleted file mode 100644 index 887fd80..0000000 --- a/src/it/log-gcp-with-service/invoker.properties +++ /dev/null @@ -1,3 +0,0 @@ -invoker.environmentVariables.LOGBACK_APPENDER=GCP -invoker.environmentVariables.SERVICE_NAME=test-service -invoker.environmentVariables.SERVICE_VERSION=0.1.2 diff --git a/src/it/log-gcp-with-service/pom.xml b/src/it/log-gcp-with-service/pom.xml deleted file mode 100644 index 0f81f40..0000000 --- a/src/it/log-gcp-with-service/pom.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 4.0.0 - - - io.kokuwa.micronaut - mirconaut-logging-it - LOCAL-SNAPSHOT - - - mirconaut-logging-it-log-gcp-with-service - - - - io.micronaut.serde - micronaut-serde-jsonp - - - diff --git a/src/it/log-gcp-with-service/postbuild.bsh b/src/it/log-gcp-with-service/postbuild.bsh deleted file mode 100644 index 6264c10..0000000 --- a/src/it/log-gcp-with-service/postbuild.bsh +++ /dev/null @@ -1,21 +0,0 @@ -// verify log - -String expected = "^\\{\"time\":\"202[3-9]-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{0,3}Z\",\"severity\":\"INFO\",\"thread\":\"main\",\"logger\":\"io.kokuwa.micronaut.logging.LoggingTest\",\"message\":\"test-output-marker\",\"raw-message\":\"test-output-marker\",\"serviceContext\":\\{\"service\":\"test-service\",\"version\":\"0.1.2\"}}$"; -String[] logs = org.codehaus.plexus.util.FileUtils.fileRead(basedir + "/build.log").split("\n"); - -for (String log : logs) { - if (!log.contains("test-output-marker")) { - continue; - } - if (java.util.regex.Pattern.matches(expected, log)) { - return true; - } else { - System.out.println("marker found, but formatting invalid:"); - System.out.println("[EXPECTED] " + expected); - System.out.println("[ACTUAL] " + log); - return false; - } -} - -System.out.println("marker not found"); -return false; diff --git a/src/it/log-json-from-env-serde-jackson/invoker.properties b/src/it/log-json-from-env-serde-jackson/invoker.properties deleted file mode 100644 index 08de0de..0000000 --- a/src/it/log-json-from-env-serde-jackson/invoker.properties +++ /dev/null @@ -1 +0,0 @@ -invoker.environmentVariables.LOGBACK_APPENDER=JSON diff --git a/src/it/log-json-from-env-serde-jackson/pom.xml b/src/it/log-json-from-env-serde-jackson/pom.xml deleted file mode 100644 index 87283dd..0000000 --- a/src/it/log-json-from-env-serde-jackson/pom.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 4.0.0 - - - io.kokuwa.micronaut - mirconaut-logging-it - LOCAL-SNAPSHOT - - - mirconaut-logging-it-log-json-from-env-serde-jackson - - - - io.micronaut.serde - micronaut-serde-jackson - - - diff --git a/src/it/log-json-from-env-serde-jackson/postbuild.bsh b/src/it/log-json-from-env-serde-jackson/postbuild.bsh deleted file mode 100644 index 0693fe0..0000000 --- a/src/it/log-json-from-env-serde-jackson/postbuild.bsh +++ /dev/null @@ -1,21 +0,0 @@ -// verify log - -String expected = "^\\{\"timestamp\":\"[0-9]{13}\",\"level\":\"INFO\",\"thread\":\"main\",\"logger\":\"io.kokuwa.micronaut.logging.LoggingTest\",\"message\":\"test-output-marker\",\"raw-message\":\"test-output-marker\"}$"; -String[] logs = org.codehaus.plexus.util.FileUtils.fileRead(basedir + "/build.log").split("\n"); - -for (String log : logs) { - if (!log.contains("test-output-marker")) { - continue; - } - if (java.util.regex.Pattern.matches(expected, log)) { - return true; - } else { - System.out.println("marker found, but formatting invalid:"); - System.out.println("[EXPECTED] " + expected); - System.out.println("[ACTUAL] " + log); - return false; - } -} - -System.out.println("marker not found"); -return false; diff --git a/src/it/log-json-from-env-serde-jsonp/invoker.properties b/src/it/log-json-from-env-serde-jsonp/invoker.properties deleted file mode 100644 index 08de0de..0000000 --- a/src/it/log-json-from-env-serde-jsonp/invoker.properties +++ /dev/null @@ -1 +0,0 @@ -invoker.environmentVariables.LOGBACK_APPENDER=JSON diff --git a/src/it/log-json-from-env-serde-jsonp/pom.xml b/src/it/log-json-from-env-serde-jsonp/pom.xml deleted file mode 100644 index 2d0d0ad..0000000 --- a/src/it/log-json-from-env-serde-jsonp/pom.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 4.0.0 - - - io.kokuwa.micronaut - mirconaut-logging-it - LOCAL-SNAPSHOT - - - mirconaut-logging-it-log-json-from-env-serde-jsonp - - - - io.micronaut.serde - micronaut-serde-jsonp - - - diff --git a/src/it/log-json-from-env-serde-jsonp/postbuild.bsh b/src/it/log-json-from-env-serde-jsonp/postbuild.bsh deleted file mode 100644 index 0693fe0..0000000 --- a/src/it/log-json-from-env-serde-jsonp/postbuild.bsh +++ /dev/null @@ -1,21 +0,0 @@ -// verify log - -String expected = "^\\{\"timestamp\":\"[0-9]{13}\",\"level\":\"INFO\",\"thread\":\"main\",\"logger\":\"io.kokuwa.micronaut.logging.LoggingTest\",\"message\":\"test-output-marker\",\"raw-message\":\"test-output-marker\"}$"; -String[] logs = org.codehaus.plexus.util.FileUtils.fileRead(basedir + "/build.log").split("\n"); - -for (String log : logs) { - if (!log.contains("test-output-marker")) { - continue; - } - if (java.util.regex.Pattern.matches(expected, log)) { - return true; - } else { - System.out.println("marker found, but formatting invalid:"); - System.out.println("[EXPECTED] " + expected); - System.out.println("[ACTUAL] " + log); - return false; - } -} - -System.out.println("marker not found"); -return false; diff --git a/src/it/log-json-from-env-serde-missing/invoker.properties b/src/it/log-json-from-env-serde-missing/invoker.properties deleted file mode 100644 index 08de0de..0000000 --- a/src/it/log-json-from-env-serde-missing/invoker.properties +++ /dev/null @@ -1 +0,0 @@ -invoker.environmentVariables.LOGBACK_APPENDER=JSON diff --git a/src/it/log-json-from-env-serde-missing/pom.xml b/src/it/log-json-from-env-serde-missing/pom.xml deleted file mode 100644 index fcf06e0..0000000 --- a/src/it/log-json-from-env-serde-missing/pom.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - 4.0.0 - - - io.kokuwa.micronaut - mirconaut-logging-it - LOCAL-SNAPSHOT - - - mirconaut-logging-it-log-json-from-env-serde-missing - diff --git a/src/it/log-json-from-env-serde-missing/postbuild.bsh b/src/it/log-json-from-env-serde-missing/postbuild.bsh deleted file mode 100644 index 465b88c..0000000 --- a/src/it/log-json-from-env-serde-missing/postbuild.bsh +++ /dev/null @@ -1,5 +0,0 @@ -// verify log - -return org.codehaus.plexus.util.FileUtils - .fileRead(basedir + "/build.log") - .contains("Failed to get object mapper from micronaut, please check your classpath"); diff --git a/src/it/log-json-from-kubernetes/invoker.properties b/src/it/log-json-from-kubernetes/invoker.properties deleted file mode 100644 index 5bba112..0000000 --- a/src/it/log-json-from-kubernetes/invoker.properties +++ /dev/null @@ -1 +0,0 @@ -invoker.environmentVariables.KUBERNETES_SERVICE_HOST=value diff --git a/src/it/log-json-from-kubernetes/pom.xml b/src/it/log-json-from-kubernetes/pom.xml deleted file mode 100644 index 20d412c..0000000 --- a/src/it/log-json-from-kubernetes/pom.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 4.0.0 - - - io.kokuwa.micronaut - mirconaut-logging-it - LOCAL-SNAPSHOT - - - mirconaut-logging-it-log-json-from-kubernetes - - - - io.micronaut.serde - micronaut-serde-jsonp - - - diff --git a/src/it/log-json-from-kubernetes/postbuild.bsh b/src/it/log-json-from-kubernetes/postbuild.bsh deleted file mode 100644 index 0693fe0..0000000 --- a/src/it/log-json-from-kubernetes/postbuild.bsh +++ /dev/null @@ -1,21 +0,0 @@ -// verify log - -String expected = "^\\{\"timestamp\":\"[0-9]{13}\",\"level\":\"INFO\",\"thread\":\"main\",\"logger\":\"io.kokuwa.micronaut.logging.LoggingTest\",\"message\":\"test-output-marker\",\"raw-message\":\"test-output-marker\"}$"; -String[] logs = org.codehaus.plexus.util.FileUtils.fileRead(basedir + "/build.log").split("\n"); - -for (String log : logs) { - if (!log.contains("test-output-marker")) { - continue; - } - if (java.util.regex.Pattern.matches(expected, log)) { - return true; - } else { - System.out.println("marker found, but formatting invalid:"); - System.out.println("[EXPECTED] " + expected); - System.out.println("[ACTUAL] " + log); - return false; - } -} - -System.out.println("marker not found"); -return false; diff --git a/src/it/log-text/pom.xml b/src/it/log-text/pom.xml deleted file mode 100644 index f89c081..0000000 --- a/src/it/log-text/pom.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - 4.0.0 - - - io.kokuwa.micronaut - mirconaut-logging-it - LOCAL-SNAPSHOT - - - mirconaut-logging-it-log-text - diff --git a/src/it/log-text/postbuild.bsh b/src/it/log-text/postbuild.bsh deleted file mode 100644 index 40e2f91..0000000 --- a/src/it/log-text/postbuild.bsh +++ /dev/null @@ -1,22 +0,0 @@ -// verify log - -String expected = "^[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{0,3} main INFO i.k.m.logging.LoggingTest test-output-marker$"; -String[] logs = org.codehaus.plexus.util.FileUtils.fileRead(basedir + "/build.log").split("\n"); - -for (String log : logs) { - if (!log.contains("test-output-marker")) { - continue; - } - if (java.util.regex.Pattern.matches(expected, log.replaceAll("\u001B\\[[;\\d]*m", ""))) { - return true; - } else { - System.out.println("marker found, but formatting invalid:"); - System.out.println("[EXPECTED] " + expected); - System.out.println("[ACTUAL] " + log); - System.out.println("[BASE64] " + Base64.getEncoder().encodeToString(log.getBytes())); - return false; - } -} - -System.out.println("marker not found"); -return false; diff --git a/src/it/logback-xml-custom/pom.xml b/src/it/logback-xml-custom/pom.xml deleted file mode 100644 index f89c081..0000000 --- a/src/it/logback-xml-custom/pom.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - 4.0.0 - - - io.kokuwa.micronaut - mirconaut-logging-it - LOCAL-SNAPSHOT - - - mirconaut-logging-it-log-text - diff --git a/src/it/logback-xml-custom/postbuild.bsh b/src/it/logback-xml-custom/postbuild.bsh deleted file mode 100644 index c6a3d94..0000000 --- a/src/it/logback-xml-custom/postbuild.bsh +++ /dev/null @@ -1,21 +0,0 @@ -// verify log - -String expected = "^TRACE io.kokuwa.micronaut.logging.LoggingTest test-output-marker$"; -String[] logs = org.codehaus.plexus.util.FileUtils.fileRead(basedir + "/build.log").split("\n"); - -for (String log : logs) { - if (!log.contains("test-output-marker")) { - continue; - } - if (java.util.regex.Pattern.matches(expected, log)) { - return true; - } else { - System.out.println("marker found, but formatting invalid:"); - System.out.println("[EXPECTED] " + expected); - System.out.println("[ACTUAL] " + log); - return false; - } -} - -System.out.println("marker not found"); -return false; diff --git a/src/it/logback-xml-custom/src/test/resources/logback.xml b/src/it/logback-xml-custom/src/test/resources/logback.xml deleted file mode 100644 index a704605..0000000 --- a/src/it/logback-xml-custom/src/test/resources/logback.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - %-5level %logger{40} %msg%n - - - - - - - - diff --git a/src/it/pom.xml b/src/it/pom.xml deleted file mode 100644 index d08c441..0000000 --- a/src/it/pom.xml +++ /dev/null @@ -1,122 +0,0 @@ - - - 4.0.0 - - io.kokuwa.micronaut - mirconaut-logging-it - LOCAL-SNAPSHOT - pom - - - log-text - log-json-from-env - log-json-from-kubernetes - log-gcp-from-env - log-gcp-from-gcloud - level-from-micronaut - logback-xml-custom - - - - 2025-06-27T00:00:00Z - UTF-8 - 17 - - - - - - io.kokuwa.micronaut - micronaut-logging - @project.version@ - - - io.micronaut.platform - micronaut-platform - 4.9.0 - pom - import - - - - - - - - io.micronaut - micronaut-runtime - - - io.micronaut.test - micronaut-test-junit5 - test - - - io.kokuwa.micronaut - micronaut-logging - runtime - - - - - - ${project.basedir}/../src/test/java - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.14.0 - - class - true - true - true - -Xlint:all,-processing - - - io.micronaut - micronaut-inject-java - - - - - - org.apache.maven.plugins - maven-resources-plugin - 3.3.1 - - - org.apache.maven.plugins - maven-surefire-plugin - 3.5.3 - - - - - - - - org.apache.maven.plugins - maven-resources-plugin - - - default-resources - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - default-compile - - - - - - - - diff --git a/src/it/src/test/java/io/kokuwa/micronaut/logging/LoggingTest.java b/src/it/src/test/java/io/kokuwa/micronaut/logging/LoggingTest.java deleted file mode 100644 index 2d8463a..0000000 --- a/src/it/src/test/java/io/kokuwa/micronaut/logging/LoggingTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.kokuwa.micronaut.logging; - -@io.micronaut.test.extensions.junit5.annotation.MicronautTest -public class LoggingTest { - - @org.junit.jupiter.api.Test - void log() { - var log = org.slf4j.LoggerFactory.getLogger(LoggingTest.class); - log.trace("test-output-marker"); - log.debug("test-output-marker"); - log.info("test-output-marker"); - } -} diff --git a/src/main/java/io/kokuwa/micronaut/logging/LogbackUtil.java b/src/main/java/io/kokuwa/micronaut/logging/LogbackUtil.java index bb21701..625191e 100644 --- a/src/main/java/io/kokuwa/micronaut/logging/LogbackUtil.java +++ b/src/main/java/io/kokuwa/micronaut/logging/LogbackUtil.java @@ -4,7 +4,7 @@ import java.util.Objects; import java.util.Optional; import java.util.function.Supplier; -import jakarta.inject.Singleton; +import javax.inject.Singleton; import org.slf4j.LoggerFactory; @@ -12,6 +12,7 @@ import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.turbo.TurboFilter; import io.micronaut.context.annotation.BootstrapContextCompatible; import io.micronaut.context.annotation.Requires; +import io.micronaut.core.annotation.Internal; /** * Utility class for Logback operations. @@ -21,6 +22,7 @@ import io.micronaut.context.annotation.Requires; @Requires(classes = LoggerContext.class) @BootstrapContextCompatible @Singleton +@Internal public class LogbackUtil { private final LoggerContext context; diff --git a/src/main/java/io/kokuwa/micronaut/logging/layout/GcpJsonLayout.java b/src/main/java/io/kokuwa/micronaut/logging/StackdriverJsonLayout.java similarity index 62% rename from src/main/java/io/kokuwa/micronaut/logging/layout/GcpJsonLayout.java rename to src/main/java/io/kokuwa/micronaut/logging/StackdriverJsonLayout.java index 524601c..a609ca1 100644 --- a/src/main/java/io/kokuwa/micronaut/logging/layout/GcpJsonLayout.java +++ b/src/main/java/io/kokuwa/micronaut/logging/StackdriverJsonLayout.java @@ -1,33 +1,48 @@ -package io.kokuwa.micronaut.logging.layout; +package io.kokuwa.micronaut.logging; import java.time.Instant; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.contrib.jackson.JacksonJsonFormatter; +import ch.qos.logback.contrib.json.classic.JsonLayout; import io.micronaut.core.util.StringUtils; +import lombok.Getter; +import lombok.Setter; /** - * GCP logging layout. + * Stackdriver layout. * * @author Stephan Schnabel * @see "https://cloud.google.com/logging/docs/agent/configuration#process-payload" * @see "https://cloud.google.com/error-reporting/reference/rest/v1beta1/ServiceContext" */ -public class GcpJsonLayout extends JsonLayout { +@Getter +@Setter +public class StackdriverJsonLayout extends JsonLayout { - private static final String UNDEFINED = "_IS_UNDEFINED"; - private static final String TIME_ATTR_NAME = "time"; + private static final String TIMESTAMP_ATTR_NAME = "time"; private static final String SEVERITY_ATTR_NAME = "severity"; private Map serviceContext; private String serviceName; private String serviceVersion; + private boolean includeExceptionInMessage; + + public StackdriverJsonLayout() { + appendLineSeparator = true; + includeContextName = false; + includeMessage = true; + includeExceptionInMessage = true; + setJsonFormatter(new JacksonJsonFormatter()); + } @Override protected Map toJsonMap(ILoggingEvent event) { var map = new LinkedHashMap(); - add(TIME_ATTR_NAME, includeTimestamp, Instant.ofEpochMilli(event.getTimeStamp()).toString(), map); + add(TIMESTAMP_ATTR_NAME, includeTimestamp, Instant.ofEpochMilli(event.getTimeStamp()).toString(), map); add(SEVERITY_ATTR_NAME, includeLevel, String.valueOf(event.getLevel()), map); add(THREAD_ATTR_NAME, includeThreadName, event.getThreadName(), map); add(CONTEXT_ATTR_NAME, includeContextName, event.getLoggerContextVO().getName(), map); @@ -35,18 +50,18 @@ public class GcpJsonLayout extends JsonLayout { addMap(MDC_ATTR_NAME, includeMDC, event.getMDCPropertyMap(), map); add(FORMATTED_MESSAGE_ATTR_NAME, includeFormattedMessage, event.getFormattedMessage(), map); add(MESSAGE_ATTR_NAME, includeMessage, event.getMessage(), map); - addThrowableInfo(EXCEPTION_ATTR_NAME, includeException, event, map); + addThrowableInfo(JsonLayout.EXCEPTION_ATTR_NAME, includeException, event, map); addServiceContext(map); return map; } private void addServiceContext(Map map) { if (serviceContext == null) { - serviceContext = new LinkedHashMap<>(2); - if (StringUtils.isNotEmpty(serviceName) && !serviceName.endsWith(UNDEFINED)) { + serviceContext = new HashMap<>(2); + if (StringUtils.isNotEmpty(serviceName)) { serviceContext.put("service", serviceName); } - if (StringUtils.isNotEmpty(serviceVersion) && !serviceVersion.endsWith(UNDEFINED)) { + if (StringUtils.isNotEmpty(serviceVersion)) { serviceContext.put("version", serviceVersion); } } @@ -54,12 +69,4 @@ public class GcpJsonLayout extends JsonLayout { map.put("serviceContext", serviceContext); } } - - public void setServiceName(String serviceName) { - this.serviceName = serviceName; - } - - public void setServiceVersion(String serviceVersion) { - this.serviceVersion = serviceVersion; - } } diff --git a/src/main/java/io/kokuwa/micronaut/logging/configurator/DefaultConfigurator.java b/src/main/java/io/kokuwa/micronaut/logging/configurator/DefaultConfigurator.java deleted file mode 100644 index 3b1a51a..0000000 --- a/src/main/java/io/kokuwa/micronaut/logging/configurator/DefaultConfigurator.java +++ /dev/null @@ -1,43 +0,0 @@ -package io.kokuwa.micronaut.logging.configurator; - -import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.spi.Configurator; -import ch.qos.logback.classic.util.DefaultJoranConfigurator; -import ch.qos.logback.core.joran.spi.JoranException; -import ch.qos.logback.core.spi.ContextAwareBase; - -/** - * Use logback-default.xml if no configuration is provided by user. - * - * @author Stephan Schnabel - */ -public class DefaultConfigurator extends ContextAwareBase implements Configurator { - - @SuppressWarnings("deprecation") - @Override - public ExecutionStatus configure(LoggerContext loggerContext) { - - if (new DefaultJoranConfigurator().findURLOfDefaultConfigurationFile(false) != null) { - // there is a default logback file, use this one instead of our default - return ExecutionStatus.INVOKE_NEXT_IF_ANY; - } - - var base = DefaultConfigurator.class.getResource("/io/kokuwa/logback/logback-default.xml"); - if (base == null) { - addError("Failed to find logback.xml from io.kokuwa:micronaut-logging"); - return ExecutionStatus.NEUTRAL; - } - - try { - addInfo("Use logback.xml from io.kokuwa:micronaut-logging"); - var configurator = new MicronautJoranConfigurator(); - configurator.setContext(loggerContext); - configurator.doConfigure(base); - } catch (JoranException e) { - addError("Failed to load logback.xml from io.kokuwa:micronaut-logging", e); - return ExecutionStatus.NEUTRAL; - } - - return ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY; - } -} diff --git a/src/main/java/io/kokuwa/micronaut/logging/configurator/MicronautJoranConfigurator.java b/src/main/java/io/kokuwa/micronaut/logging/configurator/MicronautJoranConfigurator.java deleted file mode 100644 index a1010d7..0000000 --- a/src/main/java/io/kokuwa/micronaut/logging/configurator/MicronautJoranConfigurator.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.kokuwa.micronaut.logging.configurator; - -import ch.qos.logback.classic.joran.JoranConfigurator; -import ch.qos.logback.core.joran.spi.ElementSelector; -import ch.qos.logback.core.joran.spi.RuleStore; - -/** - * Add custom actions. - * - * @author Stephan Schnabel - */ -public class MicronautJoranConfigurator extends JoranConfigurator { - - @Override - public void addElementSelectorAndActionAssociations(RuleStore rs) { - super.addElementSelectorAndActionAssociations(rs); - rs.addRule(new ElementSelector("configuration/root/autoAppender"), () -> new RootAutoSelectAppenderAction()); - } -} diff --git a/src/main/java/io/kokuwa/micronaut/logging/configurator/RootAutoSelectAppenderAction.java b/src/main/java/io/kokuwa/micronaut/logging/configurator/RootAutoSelectAppenderAction.java deleted file mode 100644 index 1d0db03..0000000 --- a/src/main/java/io/kokuwa/micronaut/logging/configurator/RootAutoSelectAppenderAction.java +++ /dev/null @@ -1,130 +0,0 @@ -package io.kokuwa.micronaut.logging.configurator; - -import java.util.Optional; - -import ch.qos.logback.classic.Logger; -import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.PatternLayout; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.ConsoleAppender; -import ch.qos.logback.core.Layout; -import ch.qos.logback.core.encoder.LayoutWrappingEncoder; -import ch.qos.logback.core.joran.action.Action; -import ch.qos.logback.core.joran.spi.SaxEventInterpretationContext; -import io.kokuwa.micronaut.logging.layout.GcpJsonLayout; -import io.kokuwa.micronaut.logging.layout.JsonLayout; -import io.micronaut.core.util.StringUtils; - -/** - * Auto select appender by environment. - * - * @author Stephan Schnabel - */ -public class RootAutoSelectAppenderAction extends Action { - - private static final boolean IS_KUBERNETES = StringUtils.isNotEmpty(System.getenv("KUBERNETES_SERVICE_HOST")); - private static final boolean IS_GCP = StringUtils.isNotEmpty(System.getenv("GOOGLE_CLOUD_PROJECT")); - - private static final String APPENDER_CONSOLE = "CONSOLE"; - private static final String APPENDER_JSON = "JSON"; - private static final String APPENDER_GCP = "GCP"; - private static final String LOGBACK_APPENDER = "LOGBACK_APPENDER"; - private static final String LOGBACK_PATTERN = "LOGBACK_PATTERN"; - private static final String LOGBACK_PATTERN_DEFAULT = """ - %cyan(%d{HH:mm:ss.SSS}) \ - %gray(%-6.6thread) \ - %highlight(%-5level) \ - %magenta(%32logger{32}) \ - %mdc \ - %msg%n"""; - - @Override - public void begin(SaxEventInterpretationContext ic, String name, org.xml.sax.Attributes attributes) { - - var rootLogger = LoggerContext.class.cast(context).getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); - var rootLoggerAppenders = rootLogger.iteratorForAppenders(); - if (rootLoggerAppenders.hasNext()) { - addWarn("Skip because appender already found: " + rootLoggerAppenders.next().getName()); - return; - } - - var envAppender = env(LOGBACK_APPENDER, null); - if (envAppender != null) { - setAppender(rootLogger, envAppender); - return; - } - - if (IS_KUBERNETES) { - setAppender(rootLogger, APPENDER_JSON); - return; - } - if (IS_GCP) { - setAppender(rootLogger, APPENDER_GCP); - return; - } - setAppender(rootLogger, APPENDER_CONSOLE); - } - - @Override - public void end(SaxEventInterpretationContext ic, String name) {} - - private void setAppender(Logger rootLogger, String appenderName) { - addInfo("Use appender: " + appenderName); - - var layout = switch (appenderName) { - case APPENDER_JSON -> json(); - case APPENDER_GCP -> gcp(); - case APPENDER_CONSOLE -> console(); - default -> { - addError("Appender " + appenderName + " not found. Using console ..."); - yield console(); - } - }; - layout.start(); - - var encoder = new LayoutWrappingEncoder(); - encoder.setContext(context); - encoder.setLayout(layout); - encoder.start(); - - var appender = new ConsoleAppender(); - appender.setContext(context); - appender.setName(appenderName); - appender.setEncoder(encoder); - appender.start(); - - rootLogger.addAppender(appender); - } - - private Layout console() { - var layout = new PatternLayout(); - layout.setContext(context); - layout.setPattern(env(LOGBACK_PATTERN, LOGBACK_PATTERN_DEFAULT)); - return layout; - } - - private Layout json() { - var layout = new JsonLayout(); - layout.setContext(context); - return layout; - } - - private Layout gcp() { - var layout = new GcpJsonLayout(); - layout.setContext(context); - layout.setServiceName(env("SERVICE_NAME", null)); - layout.setServiceVersion(env("SERVICE_VERSION", null)); - return layout; - } - - private String env(String name, String defaultValue) { - var envValue = Optional.ofNullable(System.getenv(name)).map(String::trim).filter(StringUtils::isNotEmpty); - var finalValue = envValue.orElse(defaultValue); - if (envValue.isPresent()) { - addInfo("Use provided config: " + name + "=" + finalValue); - } else { - addInfo("Use default config: " + name + "=" + finalValue); - } - return finalValue; - } -} diff --git a/src/main/java/io/kokuwa/micronaut/logging/http/AbstractMdcFilter.java b/src/main/java/io/kokuwa/micronaut/logging/http/AbstractMdcFilter.java deleted file mode 100644 index b4634be..0000000 --- a/src/main/java/io/kokuwa/micronaut/logging/http/AbstractMdcFilter.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.kokuwa.micronaut.logging.http; - -import java.util.Map; - -import org.reactivestreams.Publisher; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; - -import io.micronaut.core.async.publisher.Publishers; -import io.micronaut.http.HttpRequest; -import io.micronaut.http.MutableHttpResponse; -import io.micronaut.http.filter.HttpServerFilter; -import io.micronaut.http.filter.ServerFilterChain; - -/** - * Base for all MDC related http filters. - * - * @author Stephan Schnabel - */ -public abstract class AbstractMdcFilter implements HttpServerFilter { - - protected final Logger log = LoggerFactory.getLogger(getClass()); - protected final int order; - protected final String prefix; - - protected AbstractMdcFilter(Integer order, String prefix) { - this.order = order; - this.prefix = prefix; - } - - @Override - public int getOrder() { - return order; - } - - protected Publisher> doFilter( - HttpRequest request, - ServerFilterChain chain, - Map mdc) { - - if (mdc.isEmpty()) { - return chain.proceed(request); - } - - mdc.forEach((key, value) -> MDC.put(addPrefix(key), value)); - return Publishers.map(chain.proceed(request), response -> { - mdc.keySet().forEach(key -> MDC.remove(addPrefix(key))); - return response; - }); - } - - private String addPrefix(String key) { - return prefix == null ? key : prefix + key; - } -} diff --git a/src/main/java/io/kokuwa/micronaut/logging/http/mdc/AuthenticationMdcFilter.java b/src/main/java/io/kokuwa/micronaut/logging/http/mdc/AuthenticationMdcFilter.java deleted file mode 100644 index adc2946..0000000 --- a/src/main/java/io/kokuwa/micronaut/logging/http/mdc/AuthenticationMdcFilter.java +++ /dev/null @@ -1,77 +0,0 @@ -package io.kokuwa.micronaut.logging.http.mdc; - -import java.util.HashMap; -import java.util.Optional; -import java.util.Set; - -import org.reactivestreams.Publisher; - -import io.kokuwa.micronaut.logging.http.AbstractMdcFilter; -import io.micronaut.context.annotation.Requires; -import io.micronaut.context.annotation.Value; -import io.micronaut.core.util.StringUtils; -import io.micronaut.http.HttpRequest; -import io.micronaut.http.MutableHttpResponse; -import io.micronaut.http.annotation.Filter; -import io.micronaut.http.filter.ServerFilterChain; -import io.micronaut.http.filter.ServerFilterPhase; -import io.micronaut.runtime.context.scope.Refreshable; -import io.micronaut.security.authentication.Authentication; - -/** - * Filter to add claims from authentication to MDC. - * - * @author Stephan Schnabel - */ -@Refreshable -@Requires(classes = Authentication.class) -@Requires(property = AuthenticationMdcFilter.PREFIX + ".enabled", notEquals = StringUtils.FALSE) -@Filter("${" + AuthenticationMdcFilter.PREFIX + ".path:/**}") -public class AuthenticationMdcFilter extends AbstractMdcFilter { - - public static final String PREFIX = "logger.http.authentication"; - public static final String DEFAULT_NAME = "principal"; - public static final int DEFAULT_ORDER = ServerFilterPhase.SECURITY.after(); - - private final String name; - private final Set attributes; - - public AuthenticationMdcFilter( - @Value("${" + PREFIX + ".name}") Optional name, - @Value("${" + PREFIX + ".attributes}") Optional> attributes, - @Value("${" + PREFIX + ".prefix}") Optional prefix, - @Value("${" + PREFIX + ".order}") Optional order) { - super(order.orElse(DEFAULT_ORDER), prefix.orElse(null)); - this.name = name.orElse(DEFAULT_NAME); - this.attributes = attributes.orElseGet(Set::of); - if (name.isPresent() || !this.attributes.isEmpty()) { - log.info("Configured with name {} and attributes {}", this.name, this.attributes); - } - } - - @Override - public Publisher> doFilter(HttpRequest request, ServerFilterChain chain) { - - // get authentication - - var authenticationOptional = request.getUserPrincipal(Authentication.class); - if (authenticationOptional.isEmpty()) { - return chain.proceed(request); - } - var authentication = authenticationOptional.get(); - var authenticationAttributes = authentication.getAttributes(); - - // add mdc - - var mdc = new HashMap(); - mdc.put(name, authentication.getName()); - for (var attibuteName : attributes) { - var attibuteValue = authenticationAttributes.get(attibuteName); - if (attibuteValue != null) { - mdc.put(attibuteName, String.valueOf(attibuteValue)); - } - } - - return doFilter(request, chain, mdc); - } -} diff --git a/src/main/java/io/kokuwa/micronaut/logging/http/mdc/HeaderMdcFilter.java b/src/main/java/io/kokuwa/micronaut/logging/http/mdc/HeaderMdcFilter.java deleted file mode 100644 index a5a8b85..0000000 --- a/src/main/java/io/kokuwa/micronaut/logging/http/mdc/HeaderMdcFilter.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.kokuwa.micronaut.logging.http.mdc; - -import java.util.HashMap; -import java.util.List; -import java.util.Optional; - -import org.reactivestreams.Publisher; - -import io.kokuwa.micronaut.logging.http.AbstractMdcFilter; -import io.micronaut.context.annotation.Requires; -import io.micronaut.context.annotation.Value; -import io.micronaut.core.util.StringUtils; -import io.micronaut.http.HttpRequest; -import io.micronaut.http.MutableHttpResponse; -import io.micronaut.http.annotation.Filter; -import io.micronaut.http.filter.ServerFilterChain; -import io.micronaut.http.filter.ServerFilterPhase; -import io.micronaut.runtime.context.scope.Refreshable; - -/** - * Filter to add http headers to MDC. - * - * @author Stephan Schnabel - */ -@Refreshable -@Requires(property = HeaderMdcFilter.PREFIX + ".enabled", notEquals = StringUtils.FALSE) -@Requires(property = HeaderMdcFilter.PREFIX + ".names") -@Filter("${" + HeaderMdcFilter.PREFIX + ".path:/**}") -public class HeaderMdcFilter extends AbstractMdcFilter { - - public static final String PREFIX = "logger.http.header"; - public static final int DEFAULT_ORDER = ServerFilterPhase.FIRST.before(); - - private final List headers; - - public HeaderMdcFilter( - @Value("${" + PREFIX + ".names}") List headers, - @Value("${" + PREFIX + ".prefix}") Optional prefix, - @Value("${" + PREFIX + ".order}") Optional order) { - super(order.orElse(DEFAULT_ORDER), prefix.orElse(null)); - this.headers = headers.stream().map(String::toLowerCase).toList(); - log.info("Configured with header names {}", headers); - } - - @Override - public Publisher> doFilter(HttpRequest request, ServerFilterChain chain) { - var mdc = new HashMap(); - for (var header : headers) { - request.getHeaders().getFirst(header).ifPresent(value -> mdc.put(header, String.valueOf(value))); - } - return doFilter(request, chain, mdc); - } -} diff --git a/src/main/java/io/kokuwa/micronaut/logging/http/mdc/PathMdcFilter.java b/src/main/java/io/kokuwa/micronaut/logging/http/mdc/PathMdcFilter.java deleted file mode 100644 index 848e34d..0000000 --- a/src/main/java/io/kokuwa/micronaut/logging/http/mdc/PathMdcFilter.java +++ /dev/null @@ -1,86 +0,0 @@ -package io.kokuwa.micronaut.logging.http.mdc; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import org.reactivestreams.Publisher; - -import io.kokuwa.micronaut.logging.http.AbstractMdcFilter; -import io.micronaut.context.annotation.Requires; -import io.micronaut.context.annotation.Value; -import io.micronaut.core.util.StringUtils; -import io.micronaut.http.HttpRequest; -import io.micronaut.http.MutableHttpResponse; -import io.micronaut.http.annotation.Filter; -import io.micronaut.http.filter.ServerFilterChain; -import io.micronaut.http.filter.ServerFilterPhase; -import io.micronaut.runtime.context.scope.Refreshable; - -/** - * Filter to add request path parts to MDC. - * - * @author Stephan Schnabel - */ -@Refreshable -@Requires(property = PathMdcFilter.PREFIX + ".enabled", notEquals = StringUtils.FALSE) -@Requires(property = PathMdcFilter.PREFIX + ".patterns") -@Filter("${" + PathMdcFilter.PREFIX + ".path:/**}") -public class PathMdcFilter extends AbstractMdcFilter { - - public static final String PREFIX = "logger.http.path"; - public static final int DEFAULT_ORDER = ServerFilterPhase.FIRST.before(); - public static final Pattern PATTERN_GROUPS = Pattern.compile("\\(\\?<([a-zA-Z][a-zA-Z0-9]+)>"); - - private final Map> patternsWithGroups; - - public PathMdcFilter( - @Value("${" + PREFIX + ".patterns}") List patterns, - @Value("${" + PREFIX + ".prefix}") Optional prefix, - @Value("${" + PREFIX + ".order}") Optional order) { - super(order.orElse(DEFAULT_ORDER), prefix.orElse(null)); - this.patternsWithGroups = new HashMap<>(); - for (var patternString : patterns) { - try { - var pattern = Pattern.compile(patternString); - var groupMatcher = PATTERN_GROUPS.matcher(pattern.toString()); - var groups = new HashSet(); - while (groupMatcher.find()) { - groups.add(groupMatcher.group(1)); - } - - if (groups.isEmpty()) { - log.warn("Path {} is missing groups.", patternString); - } else { - log.info("Added path {} with groups {}.", patternString, groups); - patternsWithGroups.put(pattern, groups); - } - } catch (PatternSyntaxException e) { - log.warn("Path {} is invalid.", patternString); - } - } - } - - @Override - public Publisher> doFilter(HttpRequest request, ServerFilterChain chain) { - - var mdc = new HashMap(); - var path = request.getPath(); - - for (var patternWithGroup : patternsWithGroups.entrySet()) { - var matcher = patternWithGroup.getKey().matcher(path); - if (matcher.matches()) { - for (var group : patternWithGroup.getValue()) { - mdc.put(group, matcher.group(group)); - } - } - } - - return doFilter(request, chain, mdc); - } -} diff --git a/src/main/java/io/kokuwa/micronaut/logging/layout/JsonLayout.java b/src/main/java/io/kokuwa/micronaut/logging/layout/JsonLayout.java deleted file mode 100644 index 4665494..0000000 --- a/src/main/java/io/kokuwa/micronaut/logging/layout/JsonLayout.java +++ /dev/null @@ -1,197 +0,0 @@ -package io.kokuwa.micronaut.logging.layout; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.TimeZone; - -import ch.qos.logback.classic.pattern.ThrowableHandlingConverter; -import ch.qos.logback.classic.pattern.ThrowableProxyConverter; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.CoreConstants; -import ch.qos.logback.core.LayoutBase; -import ch.qos.logback.core.status.OnConsoleStatusListener; -import ch.qos.logback.core.status.StatusUtil; -import ch.qos.logback.core.util.StatusListenerConfigHelper; -import io.micronaut.http.MediaType; -import io.micronaut.json.JsonMapper; - -public class JsonLayout extends LayoutBase { - - public static final String TIMESTAMP_ATTR_NAME = "timestamp"; - public static final String LEVEL_ATTR_NAME = "level"; - public static final String THREAD_ATTR_NAME = "thread"; - public static final String MDC_ATTR_NAME = "mdc"; - public static final String LOGGER_ATTR_NAME = "logger"; - public static final String FORMATTED_MESSAGE_ATTR_NAME = "message"; - public static final String MESSAGE_ATTR_NAME = "raw-message"; - public static final String EXCEPTION_ATTR_NAME = "exception"; - public static final String CONTEXT_ATTR_NAME = "context"; - - protected boolean includeLevel = true; - protected boolean includeThreadName = true; - protected boolean includeMDC = true; - protected boolean includeLoggerName = true; - protected boolean includeFormattedMessage = true; - protected boolean includeMessage = true; - protected boolean includeException = true; - protected boolean includeContextName = false; - protected boolean includeTimestamp = true; - private String timestampFormat; - private String timestampFormatTimezoneId; - private ThrowableHandlingConverter throwableHandlingConverter = new ThrowableProxyConverter(); - private JsonMapper mapper; - - @Override - public String getContentType() { - return MediaType.APPLICATION_JSON; - } - - @Override - public void start() { - this.throwableHandlingConverter.start(); - super.start(); - } - - @Override - public void stop() { - super.stop(); - this.throwableHandlingConverter.stop(); - } - - @Override - public String doLayout(ILoggingEvent event) { - var map = toJsonMap(event); - - if (mapper == null) { - try { - mapper = JsonMapper.createDefault(); - } catch (IllegalStateException e) { - if (!StatusUtil.contextHasStatusListener(context)) { - addError("Failed to get object mapper from micronaut, please check your classpath"); - StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener()); - } - return map.toString() + CoreConstants.LINE_SEPARATOR; - } - } - - try { - return new String(mapper.writeValueAsBytes(map), StandardCharsets.UTF_8) + CoreConstants.LINE_SEPARATOR; - } catch (IOException e) { - addError("Failed to write json from event " + event + " and map " + map, e); - return null; - } - } - - protected Map toJsonMap(ILoggingEvent event) { - var map = new LinkedHashMap(); - addTimestamp(TIMESTAMP_ATTR_NAME, includeTimestamp, event.getTimeStamp(), map); - add(LEVEL_ATTR_NAME, includeLevel, String.valueOf(event.getLevel()), map); - add(THREAD_ATTR_NAME, includeThreadName, event.getThreadName(), map); - addMap(MDC_ATTR_NAME, includeMDC, event.getMDCPropertyMap(), map); - add(LOGGER_ATTR_NAME, includeLoggerName, event.getLoggerName(), map); - add(FORMATTED_MESSAGE_ATTR_NAME, includeFormattedMessage, event.getFormattedMessage(), map); - add(MESSAGE_ATTR_NAME, includeMessage, event.getMessage(), map); - add(CONTEXT_ATTR_NAME, includeContextName, event.getLoggerContextVO().getName(), map); - addThrowableInfo(EXCEPTION_ATTR_NAME, includeException, event, map); - return map; - } - - protected void addThrowableInfo(String fieldName, boolean field, ILoggingEvent value, Map map) { - if (field && value != null) { - var throwableProxy = value.getThrowableProxy(); - if (throwableProxy != null) { - var ex = throwableHandlingConverter.convert(value); - if (ex != null && !ex.isEmpty()) { - map.put(fieldName, ex); - } - } - } - } - - protected void addMap(String key, boolean field, Map mapValue, Map map) { - if (field && mapValue != null && !mapValue.isEmpty()) { - map.put(key, mapValue); - } - } - - protected void addTimestamp(String key, boolean field, long timeStamp, Map map) { - if (field) { - var formatted = formatTimestamp(timeStamp); - if (formatted != null) { - map.put(key, formatted); - } - } - } - - protected void add(String fieldName, boolean field, String value, Map map) { - if (field && value != null) { - map.put(fieldName, value); - } - } - - protected String formatTimestamp(long timestamp) { - if (timestampFormat == null || timestamp < 0) { - return String.valueOf(timestamp); - } - var date = new Date(timestamp); - var format = new SimpleDateFormat(timestampFormat); - if (timestampFormatTimezoneId != null) { - format.setTimeZone(TimeZone.getTimeZone(timestampFormatTimezoneId)); - } - return format.format(date); - } - - // setter - - public void setIncludeLevel(boolean includeLevel) { - this.includeLevel = includeLevel; - } - - public void setIncludeThreadName(boolean includeThreadName) { - this.includeThreadName = includeThreadName; - } - - public void setIncludeMDC(boolean includeMDC) { - this.includeMDC = includeMDC; - } - - public void setIncludeLoggerName(boolean includeLoggerName) { - this.includeLoggerName = includeLoggerName; - } - - public void setIncludeFormattedMessage(boolean includeFormattedMessage) { - this.includeFormattedMessage = includeFormattedMessage; - } - - public void setIncludeMessage(boolean includeMessage) { - this.includeMessage = includeMessage; - } - - public void setIncludeException(boolean includeException) { - this.includeException = includeException; - } - - public void setIncludeContextName(boolean includeContextName) { - this.includeContextName = includeContextName; - } - - public void setIncludeTimestamp(boolean includeTimestamp) { - this.includeTimestamp = includeTimestamp; - } - - public void setTimestampFormat(String timestampFormat) { - this.timestampFormat = timestampFormat; - } - - public void setTimestampFormatTimezoneId(String timestampFormatTimezoneId) { - this.timestampFormatTimezoneId = timestampFormatTimezoneId; - } - - public void setThrowableHandlingConverter(ThrowableHandlingConverter throwableHandlingConverter) { - this.throwableHandlingConverter = throwableHandlingConverter; - } -} diff --git a/src/main/java/io/kokuwa/micronaut/logging/mdc/MDCTurboFilter.java b/src/main/java/io/kokuwa/micronaut/logging/mdc/MDCTurboFilter.java index db4d805..c6f01b1 100644 --- a/src/main/java/io/kokuwa/micronaut/logging/mdc/MDCTurboFilter.java +++ b/src/main/java/io/kokuwa/micronaut/logging/mdc/MDCTurboFilter.java @@ -50,13 +50,7 @@ public class MDCTurboFilter extends TurboFilter { } @Override - public FilterReply decide( - Marker marker, - Logger logger, - Level eventLevel, - String format, - Object[] params, - Throwable t) { + public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) { if (logger == null || !isStarted()) { return FilterReply.NEUTRAL; @@ -73,6 +67,6 @@ public class MDCTurboFilter extends TurboFilter { return FilterReply.NEUTRAL; } - return eventLevel.isGreaterOrEqual(this.level) ? FilterReply.ACCEPT : FilterReply.NEUTRAL; + return level.isGreaterOrEqual(this.level) ? FilterReply.ACCEPT : FilterReply.NEUTRAL; } } diff --git a/src/main/java/io/kokuwa/micronaut/logging/mdc/MDCTurboFilterConfigurer.java b/src/main/java/io/kokuwa/micronaut/logging/mdc/MDCTurboFilterConfigurer.java index de87997..e83217c 100644 --- a/src/main/java/io/kokuwa/micronaut/logging/mdc/MDCTurboFilterConfigurer.java +++ b/src/main/java/io/kokuwa/micronaut/logging/mdc/MDCTurboFilterConfigurer.java @@ -1,71 +1,45 @@ package io.kokuwa.micronaut.logging.mdc; -import java.util.Collection; import java.util.Set; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import ch.qos.logback.classic.Level; import io.kokuwa.micronaut.logging.LogbackUtil; import io.micronaut.context.annotation.BootstrapContextCompatible; import io.micronaut.context.annotation.Context; import io.micronaut.context.annotation.Requires; import io.micronaut.context.env.Environment; +import io.micronaut.core.annotation.Internal; import io.micronaut.core.type.Argument; import io.micronaut.core.util.StringUtils; -import io.micronaut.logging.LogLevel; -import io.micronaut.logging.LoggingSystem; +import lombok.extern.slf4j.Slf4j; /** * Configure MDC filter. * * @author Stephan Schnabel */ -@BootstrapContextCompatible @Requires(beans = LogbackUtil.class) @Requires(property = MDCTurboFilterConfigurer.PREFIX) @Requires(property = MDCTurboFilterConfigurer.PREFIX + ".enabled", notEquals = StringUtils.FALSE) +@BootstrapContextCompatible @Context -public class MDCTurboFilterConfigurer implements LoggingSystem { +@Internal +@Slf4j +public class MDCTurboFilterConfigurer { public static final String PREFIX = "logger.mdc"; - private static final Logger log = LoggerFactory.getLogger(MDCTurboFilterConfigurer.class); - private final LogbackUtil logback; private final Environment environment; - private Collection mdcs = Set.of(); - private boolean initialized; - public MDCTurboFilterConfigurer(LogbackUtil logback, Environment environment) { this.logback = logback; this.environment = environment; - this.refresh(); + configure(); } - @Override - public final void refresh() { - - mdcs = environment.getPropertyEntries(PREFIX); - initialized = false; - - if (environment.getProperties("logger.levels").isEmpty()) { - log.warn("MDCs are configured, but no levels are set. MDC may not work."); - } - } - - @Override - public void setLogLevel(String name, LogLevel level) { - if (!initialized) { - configure(); - initialized = true; - } - } - - private void configure() { - for (var name : mdcs) { + public void configure() { + for (var name : environment.getPropertyEntries(PREFIX)) { var prefix = PREFIX + "." + name + "."; var key = environment.getProperty(prefix + "key", String.class, name); diff --git a/src/main/java/io/kokuwa/micronaut/logging/http/level/LogLevelClientFilter.java b/src/main/java/io/kokuwa/micronaut/logging/request/HeaderLoggingClientHttpFilter.java similarity index 62% rename from src/main/java/io/kokuwa/micronaut/logging/http/level/LogLevelClientFilter.java rename to src/main/java/io/kokuwa/micronaut/logging/request/HeaderLoggingClientHttpFilter.java index 511829d..463a070 100644 --- a/src/main/java/io/kokuwa/micronaut/logging/http/level/LogLevelClientFilter.java +++ b/src/main/java/io/kokuwa/micronaut/logging/request/HeaderLoggingClientHttpFilter.java @@ -1,4 +1,4 @@ -package io.kokuwa.micronaut.logging.http.level; +package io.kokuwa.micronaut.logging.request; import java.util.Optional; @@ -13,29 +13,30 @@ import io.micronaut.http.annotation.Filter; import io.micronaut.http.context.ServerRequestContext; import io.micronaut.http.filter.ClientFilterChain; import io.micronaut.http.filter.HttpClientFilter; +import io.micronaut.http.filter.ServerFilterPhase; /** - * Propagates log-level from server request to client. + * Http request logging filter. * * @author Stephan Schnabel */ -@Requires(beans = LogLevelServerFilter.class) -@Requires(property = LogLevelClientFilter.PREFIX + ".enabled", notEquals = StringUtils.FALSE) -@Filter("${" + LogLevelClientFilter.PREFIX + ".path:/**}") -public class LogLevelClientFilter implements HttpClientFilter { +@Requires(beans = HeaderLoggingServerHttpFilter.class) +@Requires(property = HeaderLoggingClientHttpFilter.PREFIX + ".enabled", notEquals = StringUtils.FALSE) +@Filter("${" + HeaderLoggingClientHttpFilter.PREFIX + ".path:/**}") +public class HeaderLoggingClientHttpFilter implements HttpClientFilter { - public static final String PREFIX = "logger.http.level.propagation"; - public static final int DEFAULT_ORDER = HIGHEST_PRECEDENCE; + public static final String PREFIX = "logger.request.propagation"; + public static final int DEFAULT_ORDER = ServerFilterPhase.TRACING.order(); private final String serverHeader; private final String propagationHeader; private final int order; - public LogLevelClientFilter( - @Value("${" + LogLevelServerFilter.PREFIX + ".header}") Optional serverHeader, + public HeaderLoggingClientHttpFilter( + @Value("${" + HeaderLoggingServerHttpFilter.PREFIX + ".header}") Optional serverHeader, @Value("${" + PREFIX + ".header}") Optional propagationHeader, @Value("${" + PREFIX + ".order}") Optional order) { - this.serverHeader = serverHeader.orElse(LogLevelServerFilter.DEFAULT_HEADER); + this.serverHeader = serverHeader.orElse(HeaderLoggingServerHttpFilter.DEFAULT_HEADER); this.propagationHeader = propagationHeader.orElse(this.serverHeader); this.order = order.orElse(DEFAULT_ORDER); } diff --git a/src/main/java/io/kokuwa/micronaut/logging/http/level/LogLevelServerFilter.java b/src/main/java/io/kokuwa/micronaut/logging/request/HeaderLoggingServerHttpFilter.java similarity index 50% rename from src/main/java/io/kokuwa/micronaut/logging/http/level/LogLevelServerFilter.java rename to src/main/java/io/kokuwa/micronaut/logging/request/HeaderLoggingServerHttpFilter.java index 6626fee..f0afce3 100644 --- a/src/main/java/io/kokuwa/micronaut/logging/http/level/LogLevelServerFilter.java +++ b/src/main/java/io/kokuwa/micronaut/logging/request/HeaderLoggingServerHttpFilter.java @@ -1,68 +1,83 @@ -package io.kokuwa.micronaut.logging.http.level; +package io.kokuwa.micronaut.logging.request; -import java.util.Map; import java.util.Optional; -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import org.reactivestreams.Publisher; +import org.slf4j.MDC; import ch.qos.logback.classic.turbo.TurboFilter; import io.kokuwa.micronaut.logging.LogbackUtil; -import io.kokuwa.micronaut.logging.http.AbstractMdcFilter; import io.micronaut.context.annotation.Requires; import io.micronaut.context.annotation.Value; +import io.micronaut.core.async.publisher.Publishers; import io.micronaut.core.util.StringUtils; import io.micronaut.http.HttpRequest; import io.micronaut.http.MutableHttpResponse; import io.micronaut.http.annotation.Filter; +import io.micronaut.http.filter.HttpServerFilter; import io.micronaut.http.filter.ServerFilterChain; import io.micronaut.http.filter.ServerFilterPhase; -import io.micronaut.runtime.context.scope.Refreshable; +import io.micronaut.runtime.server.EmbeddedServer; /** * Http request logging filter. * * @author Stephan Schnabel */ -@Refreshable -@Requires(property = LogLevelServerFilter.PREFIX + ".enabled", notEquals = StringUtils.FALSE) -@Filter("${" + LogLevelServerFilter.PREFIX + ".path:/**}") -public class LogLevelServerFilter extends AbstractMdcFilter { +@Requires(beans = EmbeddedServer.class) +@Requires(property = HeaderLoggingServerHttpFilter.PREFIX + ".enabled", notEquals = StringUtils.FALSE) +@Filter("${" + HeaderLoggingServerHttpFilter.PREFIX + ".path:/**}") +public class HeaderLoggingServerHttpFilter implements HttpServerFilter { + + public static final String PREFIX = "logger.request.filter"; + public static final String MDC_FILTER = PREFIX; + public static final String MDC_KEY = "level"; - public static final String PREFIX = "logger.http.level"; public static final String DEFAULT_HEADER = "x-log-level"; public static final int DEFAULT_ORDER = ServerFilterPhase.FIRST.before(); - public static final String MDC_KEY = "level"; - public static final String MDC_FILTER = PREFIX; private final LogbackUtil logback; private final String header; + private final int order; - public LogLevelServerFilter( + public HeaderLoggingServerHttpFilter( LogbackUtil logback, @Value("${" + PREFIX + ".header}") Optional header, @Value("${" + PREFIX + ".order}") Optional order) { - super(order.orElse(DEFAULT_ORDER), null); this.logback = logback; this.header = header.orElse(DEFAULT_HEADER); + this.order = order.orElse(DEFAULT_ORDER); } @PostConstruct void startTurbofilter() { - logback.getTurboFilter(LogLevelTurboFilter.class, MDC_FILTER, LogLevelTurboFilter::new).start(); + logback.getTurboFilter(HeaderLoggingTurboFilter.class, MDC_FILTER, HeaderLoggingTurboFilter::new).start(); } @PreDestroy void stopTurbofilter() { - logback.getTurboFilter(LogLevelTurboFilter.class, MDC_FILTER).ifPresent(TurboFilter::stop); + logback.getTurboFilter(HeaderLoggingTurboFilter.class, MDC_FILTER).ifPresent(TurboFilter::stop); + } + + @Override + public int getOrder() { + return order; } @Override public Publisher> doFilter(HttpRequest request, ServerFilterChain chain) { - return request.getHeaders().getFirst(header) - .map(level -> doFilter(request, chain, Map.of(MDC_KEY, level))) - .orElseGet(() -> chain.proceed(request)); + var level = request.getHeaders().getFirst(header); + if (level.isPresent()) { + MDC.put(MDC_KEY, level.get()); + return Publishers.map(chain.proceed(request), response -> { + MDC.remove(MDC_KEY); + return response; + }); + } else { + return chain.proceed(request); + } } } diff --git a/src/main/java/io/kokuwa/micronaut/logging/http/level/LogLevelTurboFilter.java b/src/main/java/io/kokuwa/micronaut/logging/request/HeaderLoggingTurboFilter.java similarity index 79% rename from src/main/java/io/kokuwa/micronaut/logging/http/level/LogLevelTurboFilter.java rename to src/main/java/io/kokuwa/micronaut/logging/request/HeaderLoggingTurboFilter.java index 57df67f..c1a8dc3 100644 --- a/src/main/java/io/kokuwa/micronaut/logging/http/level/LogLevelTurboFilter.java +++ b/src/main/java/io/kokuwa/micronaut/logging/request/HeaderLoggingTurboFilter.java @@ -1,4 +1,4 @@ -package io.kokuwa.micronaut.logging.http.level; +package io.kokuwa.micronaut.logging.request; import org.slf4j.MDC; import org.slf4j.Marker; @@ -13,7 +13,7 @@ import ch.qos.logback.core.spi.FilterReply; * * @author Stephan Schnabel */ -public class LogLevelTurboFilter extends TurboFilter { +public class HeaderLoggingTurboFilter extends TurboFilter { @Override public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) { @@ -22,7 +22,7 @@ public class LogLevelTurboFilter extends TurboFilter { return FilterReply.NEUTRAL; } - var value = MDC.get(LogLevelServerFilter.MDC_KEY); + var value = MDC.get(HeaderLoggingServerHttpFilter.MDC_KEY); if (value == null) { return FilterReply.NEUTRAL; } diff --git a/src/main/java/io/kokuwa/micronaut/logging/request/PrincipalHttpFilter.java b/src/main/java/io/kokuwa/micronaut/logging/request/PrincipalHttpFilter.java new file mode 100644 index 0000000..0e7a14d --- /dev/null +++ b/src/main/java/io/kokuwa/micronaut/logging/request/PrincipalHttpFilter.java @@ -0,0 +1,63 @@ +package io.kokuwa.micronaut.logging.request; + +import java.util.Optional; + +import org.reactivestreams.Publisher; +import org.slf4j.MDC; + +import io.micronaut.context.annotation.Requires; +import io.micronaut.context.annotation.Value; +import io.micronaut.core.async.publisher.Publishers; +import io.micronaut.core.util.StringUtils; +import io.micronaut.http.HttpRequest; +import io.micronaut.http.MutableHttpResponse; +import io.micronaut.http.annotation.Filter; +import io.micronaut.http.filter.HttpServerFilter; +import io.micronaut.http.filter.ServerFilterChain; +import io.micronaut.http.filter.ServerFilterPhase; +import io.micronaut.runtime.server.EmbeddedServer; + +/** + * Http request principal filter. + * + * @author Stephan Schnabel + */ +@Requires(beans = EmbeddedServer.class) +@Requires(property = PrincipalHttpFilter.PREFIX + ".enabled", notEquals = StringUtils.FALSE) +@Filter("${" + PrincipalHttpFilter.PREFIX + ".path:/**}") +public class PrincipalHttpFilter implements HttpServerFilter { + + public static final String PREFIX = "logger.request.principal"; + + public static final String DEFAULT_KEY = "principal"; + public static final int DEFAULT_ORDER = ServerFilterPhase.SECURITY.after(); + + private final String key; + private final int order; + + public PrincipalHttpFilter( + @Value("${" + PREFIX + ".key:" + DEFAULT_KEY + "}") String key, + @Value("${" + PREFIX + ".order}") Optional order) { + this.key = key; + this.order = order.orElse(DEFAULT_ORDER); + } + + @Override + public int getOrder() { + return order; + } + + @Override + public Publisher> doFilter(HttpRequest request, ServerFilterChain chain) { + var princial = request.getUserPrincipal(); + if (princial.isPresent()) { + MDC.put(key, princial.get().getName()); + return Publishers.map(chain.proceed(request), response -> { + MDC.remove(key); + return response; + }); + } else { + return chain.proceed(request); + } + } +} diff --git a/src/main/resources/META-INF/native-image/io.kokuwa.micronaut/micronaut-logging/native-image.properties b/src/main/resources/META-INF/native-image/io.kokuwa.micronaut/micronaut-logging/native-image.properties deleted file mode 100644 index e1e3f1f..0000000 --- a/src/main/resources/META-INF/native-image/io.kokuwa.micronaut/micronaut-logging/native-image.properties +++ /dev/null @@ -1,2 +0,0 @@ -Args = --initialize-at-build-time=io.kokuwa.micronaut.logging.configurator.RootAutoSelectAppenderAction - diff --git a/src/main/resources/META-INF/native-image/io.kokuwa.micronaut/micronaut-logging/resource-config.json b/src/main/resources/META-INF/native-image/io.kokuwa.micronaut/micronaut-logging/resource-config.json deleted file mode 100644 index 3a97089..0000000 --- a/src/main/resources/META-INF/native-image/io.kokuwa.micronaut/micronaut-logging/resource-config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "resources": { - "includes": [ - { - "pattern": "\\Qio/kokuwa/logback/logback-default.xml\\E" - }, - { - "pattern": "\\QMETA-INF/services/ch.qos.logback.classic.spi.Configurator\\E" - } - ] - } -} \ No newline at end of file diff --git a/src/main/resources/META-INF/services/ch.qos.logback.classic.spi.Configurator b/src/main/resources/META-INF/services/ch.qos.logback.classic.spi.Configurator deleted file mode 100644 index 1f9f2da..0000000 --- a/src/main/resources/META-INF/services/ch.qos.logback.classic.spi.Configurator +++ /dev/null @@ -1 +0,0 @@ -io.kokuwa.micronaut.logging.configurator.DefaultConfigurator diff --git a/src/main/resources/io/kokuwa/logback/logback-default.xml b/src/main/resources/io/kokuwa/logback/logback-default.xml deleted file mode 100644 index 78fe3f0..0000000 --- a/src/main/resources/io/kokuwa/logback/logback-default.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..42a34f7 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,25 @@ + + + + + + + true + + %cyan(%d{HH:mm:ss.SSS}) %gray(%-6.6thread) %highlight(%-5level) %magenta(%32logger{32}) %mdc %msg%n + + + + + + ${serviceName} + ${serviceVersion} + + + + + + + + + diff --git a/src/test/java/io/kokuwa/micronaut/logging/AbstractTest.java b/src/test/java/io/kokuwa/micronaut/logging/AbstractTest.java index ebcc5e7..f63e4c2 100644 --- a/src/test/java/io/kokuwa/micronaut/logging/AbstractTest.java +++ b/src/test/java/io/kokuwa/micronaut/logging/AbstractTest.java @@ -2,11 +2,11 @@ package io.kokuwa.micronaut.logging; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.MethodOrderer.Alphanumeric; import org.junit.jupiter.api.TestMethodOrder; import org.slf4j.MDC; -import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import io.micronaut.test.annotation.MicronautTest; /** * Base for tests regarding logging. @@ -14,7 +14,7 @@ import io.micronaut.test.extensions.junit5.annotation.MicronautTest; * @author Stephan Schnabel */ @MicronautTest -@TestMethodOrder(MethodOrderer.DisplayName.class) +@TestMethodOrder(Alphanumeric.class) public abstract class AbstractTest { @BeforeEach diff --git a/src/test/java/io/kokuwa/micronaut/logging/http/AbstractFilterTest.java b/src/test/java/io/kokuwa/micronaut/logging/http/AbstractFilterTest.java deleted file mode 100644 index 4587dcb..0000000 --- a/src/test/java/io/kokuwa/micronaut/logging/http/AbstractFilterTest.java +++ /dev/null @@ -1,152 +0,0 @@ -package io.kokuwa.micronaut.logging.http; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.util.Map; -import java.util.function.Consumer; - -import jakarta.inject.Inject; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; - -import ch.qos.logback.classic.Level; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.nimbusds.jose.JOSEException; -import com.nimbusds.jwt.JWTClaimsSet; -import io.kokuwa.micronaut.logging.AbstractTest; -import io.micronaut.core.annotation.Nullable; -import io.micronaut.core.util.CollectionUtils; -import io.micronaut.http.HttpHeaderValues; -import io.micronaut.http.HttpRequest; -import io.micronaut.http.HttpStatus; -import io.micronaut.http.annotation.Controller; -import io.micronaut.http.annotation.Get; -import io.micronaut.http.annotation.PathVariable; -import io.micronaut.http.client.DefaultHttpClientConfiguration; -import io.micronaut.http.client.HttpClient; -import io.micronaut.http.filter.HttpServerFilter; -import io.micronaut.runtime.server.EmbeddedServer; -import io.micronaut.security.annotation.Secured; -import io.micronaut.security.rules.SecurityRule; -import io.micronaut.security.token.jwt.signature.SignatureGeneratorConfiguration; -import io.micronaut.serde.annotation.Serdeable; -import io.micronaut.test.extensions.junit5.annotation.MicronautTest; - -/** - * Test for {@link HttpServerFilter}. - * - * @author Stephan Schnabel - */ -@MicronautTest(rebuildContext = true) -public abstract class AbstractFilterTest extends AbstractTest { - - @Inject - SignatureGeneratorConfiguration signature; - @Inject - EmbeddedServer embeddedServer; - - @DisplayName("0 - trigger rebuild of context") - @Test - void rebuild() {} - - // security - - public String token(String subject) { - return token(subject, claims -> {}); - } - - public String token(String subject, Consumer manipulator) { - var claims = new JWTClaimsSet.Builder().subject(subject); - manipulator.accept(claims); - try { - return HttpHeaderValues.AUTHORIZATION_PREFIX_BEARER + " " + signature.sign(claims.build()).serialize(); - } catch (JOSEException e) { - fail(e); - return null; - } - } - - // request - - public TestResponse get(String path, Map headers) { - - var request = HttpRequest.GET(path); - headers.forEach((name, value) -> request.header(name, value)); - var configuration = new DefaultHttpClientConfiguration(); - configuration.setLoggerName("io.kokuwa.TestClient"); - var response = HttpClient - .create(embeddedServer.getURL(), configuration) - .toBlocking().exchange(request, TestResponse.class); - assertEquals(HttpStatus.OK, response.getStatus(), "status"); - assertTrue(response.getBody().isPresent(), "body"); - assertTrue(CollectionUtils.isEmpty(MDC.getCopyOfContextMap()), "mdc leaked: " + MDC.getCopyOfContextMap()); - - return response.body(); - } - - @Secured({ SecurityRule.IS_ANONYMOUS, SecurityRule.IS_AUTHENTICATED }) - @Controller - public static class TestController { - - private static final Logger log = LoggerFactory.getLogger(TestController.class); - - @Get("/{+path}") - TestResponse run(@PathVariable String path) { - - var level = Level.OFF; - if (log.isTraceEnabled()) { - level = Level.TRACE; - } else if (log.isDebugEnabled()) { - level = Level.DEBUG; - } else if (log.isInfoEnabled()) { - level = Level.INFO; - } else if (log.isWarnEnabled()) { - level = Level.WARN; - } else if (log.isErrorEnabled()) { - level = Level.ERROR; - } - - var mdc = MDC.getCopyOfContextMap(); - log.info("Found MDC: {}", mdc); - - return new TestResponse(path, level.toString(), mdc); - } - } - - @Serdeable - public static class TestResponse { - - private final String path; - private final String level; - private final Map context; - - @JsonCreator - public TestResponse( - @JsonProperty("path") String path, - @JsonProperty("level") String level, - @Nullable @JsonProperty("context") Map context) { - this.path = path; - this.level = level; - this.context = context == null ? Map.of() : context; - } - - public String getPath() { - return path; - } - - public String getLevel() { - return level; - } - - public Map getContext() { - return context; - } - } -} diff --git a/src/test/java/io/kokuwa/micronaut/logging/http/level/LogLevelServerFilterTest.java b/src/test/java/io/kokuwa/micronaut/logging/http/level/LogLevelServerFilterTest.java deleted file mode 100644 index c4db1ef..0000000 --- a/src/test/java/io/kokuwa/micronaut/logging/http/level/LogLevelServerFilterTest.java +++ /dev/null @@ -1,80 +0,0 @@ -package io.kokuwa.micronaut.logging.http.level; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.Map; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import ch.qos.logback.classic.Level; -import io.kokuwa.micronaut.logging.http.AbstractFilterTest; -import io.micronaut.context.annotation.Property; - -/** - * Test for {@link LogLevelServerFilter}. - * - * @author Stephan Schnabel - */ -@DisplayName("http: set log level via http request") -public class LogLevelServerFilterTest extends AbstractFilterTest { - - @DisplayName("noop: disabled") - @Test - @Property(name = "logger.http.level.enabled", value = "false") - void noopDisabled() { - assertLevel(Level.INFO, "TRACE"); - } - - @DisplayName("noop: header missing") - @Test - void noopHeaderMissing() { - assertLevel(Level.INFO, null); - } - - @DisplayName("noop: header invalid, use DEBUG as default from logback") - @Test - void noopHeaderInvalid() { - assertLevel(Level.DEBUG, "TRCE"); - } - - @DisplayName("level: trace (below default)") - @Test - void levelTrace() { - assertLevel(Level.TRACE, "TRACE"); - } - - @DisplayName("level: debug (below default)") - @Test - void levelDebug() { - assertLevel(Level.DEBUG, "DEBUG"); - } - - @DisplayName("level: info (is default)") - @Test - void levelInfo() { - assertLevel(Level.INFO, "INFO"); - } - - @DisplayName("level: warn (above default)") - @Test - void levelWarn() { - assertLevel(Level.INFO, "WARN"); - } - - @DisplayName("config: custom header name") - @Test - @Property(name = "logger.http.level.header", value = "FOO") - void configHeaderWarn() { - assertLevel(Level.TRACE, "FOO", "TRACE"); - } - - private void assertLevel(Level expectedLevel, String value) { - assertLevel(expectedLevel, LogLevelServerFilter.DEFAULT_HEADER, value); - } - - private void assertLevel(Level expectedLevel, String name, String value) { - var headers = value == null ? Map.of() : Map.of(name, value); - assertEquals(expectedLevel.toString(), get("/level", headers).getLevel()); - } -} diff --git a/src/test/java/io/kokuwa/micronaut/logging/http/mdc/AuthenticationMdcFilterTest.java b/src/test/java/io/kokuwa/micronaut/logging/http/mdc/AuthenticationMdcFilterTest.java deleted file mode 100644 index d10b673..0000000 --- a/src/test/java/io/kokuwa/micronaut/logging/http/mdc/AuthenticationMdcFilterTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package io.kokuwa.micronaut.logging.http.mdc; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import io.kokuwa.micronaut.logging.http.AbstractFilterTest; -import io.micronaut.context.annotation.Property; -import io.micronaut.http.HttpHeaders; - -/** - * Test for {@link AuthenticationMdcFilter}. - * - * @author Stephan Schnabel - */ -@DisplayName("http: mdc from authentication") -public class AuthenticationMdcFilterTest extends AbstractFilterTest { - - @DisplayName("noop: disabled") - @Test - @Property(name = "logger.http.authentication.enabled", value = "false") - void noopDisabled() { - assertEquals(Map.of(), getContext(true)); - } - - @DisplayName("noop: token missing") - @Test - void noopTokenMissing() { - assertEquals(Map.of(), getContext(false)); - } - - @DisplayName("mdc: default config") - @Test - void mdcWithDefault() { - assertEquals(Map.of("principal", "mySubject"), getContext(true)); - } - - @DisplayName("mdc: with name") - @Test - @Property(name = "logger.http.authentication.name", value = "sub") - void mdcWithName() { - assertEquals(Map.of("sub", "mySubject"), getContext(true)); - } - - @DisplayName("mdc: with attribute keys") - @Test - @Property(name = "logger.http.authentication.attributes", value = "azp,aud") - void mdcWithAttributes() { - assertEquals(Map.of("principal", "mySubject", "aud", "[a, b]", "azp", "myAzp"), getContext(true)); - } - - @DisplayName("mdc: with prefix") - @Test - @Property(name = "logger.http.authentication.name", value = "sub") - @Property(name = "logger.http.authentication.attributes", value = "azp") - @Property(name = "logger.http.authentication.prefix", value = "auth.") - void mdcWithPrefix() { - assertEquals(Map.of("auth.sub", "mySubject", "auth.azp", "myAzp"), getContext(true)); - } - - private Map getContext(boolean token) { - return get("/security", token - ? Map.of(HttpHeaders.AUTHORIZATION, token("mySubject", claims -> claims - .issuer("nope") - .claim("azp", "myAzp") - .audience(List.of("a", "b")))) - : Map.of()).getContext(); - } -} diff --git a/src/test/java/io/kokuwa/micronaut/logging/http/mdc/HeaderMdcFilterTest.java b/src/test/java/io/kokuwa/micronaut/logging/http/mdc/HeaderMdcFilterTest.java deleted file mode 100644 index 489870f..0000000 --- a/src/test/java/io/kokuwa/micronaut/logging/http/mdc/HeaderMdcFilterTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.kokuwa.micronaut.logging.http.mdc; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.Map; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import io.kokuwa.micronaut.logging.http.AbstractFilterTest; -import io.micronaut.context.annotation.Property; - -/** - * Test for {@link HeaderMdcFilter}. - * - * @author Stephan Schnabel - */ -@DisplayName("http: mdc from headers") -public class HeaderMdcFilterTest extends AbstractFilterTest { - - @DisplayName("noop: empty configuration") - @Test - void noopEmptyConfiguration() { - assertContext(Map.of(), Map.of("foo", "bar")); - } - - @DisplayName("noop: disabled") - @Test - @Property(name = "logger.http.header.enabled", value = "false") - @Property(name = "logger.http.header.names", value = "foo") - void noopDisabled() { - assertContext(Map.of(), Map.of("foo", "bar")); - } - - @DisplayName("mdc: mismatch") - @Test - @Property(name = "logger.http.header.names", value = "foo") - void mdcMismatch() { - assertContext(Map.of(), Map.of("nope", "bar")); - } - - @DisplayName("mdc: match without prefix") - @Test - @Property(name = "logger.http.header.names", value = "foo") - void mdcMatchWithoutPrefix() { - assertContext(Map.of("foo", "bar"), Map.of("foo", "bar", "nope", "bar")); - } - - @DisplayName("mdc: match with prefix") - @Test - @Property(name = "logger.http.header.names", value = "foo") - @Property(name = "logger.http.header.prefix", value = "header.") - void mdcMatchWithPrefix() { - assertContext(Map.of("header.foo", "bar"), Map.of("foo", "bar", "nope", "bar")); - } - - private void assertContext(Map expectedMdcs, Map headers) { - assertEquals(expectedMdcs, get("/header", headers).getContext()); - } -} diff --git a/src/test/java/io/kokuwa/micronaut/logging/http/mdc/PathMdcFilterTest.java b/src/test/java/io/kokuwa/micronaut/logging/http/mdc/PathMdcFilterTest.java deleted file mode 100644 index 3b7ac78..0000000 --- a/src/test/java/io/kokuwa/micronaut/logging/http/mdc/PathMdcFilterTest.java +++ /dev/null @@ -1,104 +0,0 @@ -package io.kokuwa.micronaut.logging.http.mdc; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.Map; -import java.util.UUID; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import io.kokuwa.micronaut.logging.http.AbstractFilterTest; -import io.micronaut.context.annotation.Property; - -/** - * Test for {@link PathMdcFilter}. - * - * @author Stephan Schnabel - */ -@DisplayName("http: mdc from path") -public class PathMdcFilterTest extends AbstractFilterTest { - - @DisplayName("noop: empty configuration") - @Test - void noopEmptyConfiguration() { - assertContext(Map.of(), "/foo/bar"); - } - - @DisplayName("noop: disabled") - @Test - @Property(name = "logger.http.path.enabled", value = "false") - @Property(name = "logger.http.path.patterns", value = "\\/foo\\/(?[0-9]+)") - void noopDisabled() { - assertContext(Map.of(), "/foo/123"); - } - - @DisplayName("noop: misconfigured") - @Test - @Property(name = "logger.http.path.patterns", value = "\\A{") - void noopMisconfigured() { - assertContext(Map.of(), "/foo/123"); - } - - @DisplayName("noop: no group") - @Test - @Property(name = "logger.http.path.patterns", value = "\\/foo/[0-9]+") - void noopGroups() { - assertContext(Map.of(), "/foo/123"); - } - - @DisplayName("mdc: mismatch") - @Test - @Property(name = "logger.http.path.patterns", value = "\\/foo\\/(?[0-9]+)") - void mdcMismatch() { - assertContext(Map.of(), "/nope"); - assertContext(Map.of(), "/foo/abc"); - } - - @DisplayName("mdc: match with single group") - @Test - @Property(name = "logger.http.path.patterns", value = "\\/foo\\/(?[0-9]+)") - void mdcMatchWithSingleGroup() { - assertContext(Map.of("foo", "123"), "/foo/123"); - } - - @DisplayName("mdc: match with single group and prefix") - @Test - @Property(name = "logger.http.path.names", value = "foo") - @Property(name = "logger.http.path.patterns", value = "\\/foo\\/(?[0-9]+)") - @Property(name = "logger.http.path.prefix", value = "path.") - void mdcMatchWithSingleGroupAndPrefix() { - assertContext(Map.of("path.foo", "123"), "/foo/123"); - } - - @DisplayName("mdc: match with single group and misconfigured") - @Test - @Property(name = "logger.http.path.names", value = "foo") - @Property(name = "logger.http.path.patterns", value = "\\/foo\\/(?[0-9]+),\\A{") - @Property(name = "logger.http.path.prefix", value = "path.") - void mdcMatchWithSingleGroupAndMisconfigured() { - assertContext(Map.of("path.foo", "123"), "/foo/123"); - } - - @DisplayName("mdc: match with multiple group") - @Test - @Property(name = "logger.http.path.patterns", value = "/foo/(?[0-9]+)/bar/(?[0-9]+)") - void mdcMatchWithmultipleGroup() { - assertContext(Map.of("foo", "123", "bar", "456"), "/foo/123/bar/456"); - } - - @DisplayName("mdc: test for documentation example") - @Test - @Property(name = "logger.http.path.patterns", value = """ - \\/gateway\\/(?[a-f0-9\\-]{36}),\ - \\/gateway\\/(?[a-f0-9\\-]{36})\\/configuration\\/(?[a-z]+)""") - void mdcMatchExample() { - var uuid = UUID.randomUUID().toString(); - assertContext(Map.of("gatewayId", uuid), "/gateway/" + uuid); - assertContext(Map.of("gatewayId", uuid, "config", "abc"), "/gateway/" + uuid + "/configuration/abc"); - } - - private void assertContext(Map expectedMdcs, String path) { - assertEquals(expectedMdcs, get(path, Map.of()).getContext()); - } -} diff --git a/src/test/java/io/kokuwa/micronaut/logging/mdc/MDCTurboFilterTest.java b/src/test/java/io/kokuwa/micronaut/logging/mdc/MDCTurboFilterTest.java index 186c2a3..e964d2b 100644 --- a/src/test/java/io/kokuwa/micronaut/logging/mdc/MDCTurboFilterTest.java +++ b/src/test/java/io/kokuwa/micronaut/logging/mdc/MDCTurboFilterTest.java @@ -10,14 +10,14 @@ import org.slf4j.LoggerFactory; import org.slf4j.MDC; import io.kokuwa.micronaut.logging.AbstractTest; -import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import io.micronaut.test.annotation.MicronautTest; /** * Test for {@link MDCTurboFilterConfigurer}. * * @author Stephan Schnabel */ -@DisplayName("mdc based log levels") +@DisplayName("mdc") @MicronautTest(environments = "test-mdc") public class MDCTurboFilterTest extends AbstractTest { diff --git a/src/test/java/io/kokuwa/micronaut/logging/request/CompositeTest.java b/src/test/java/io/kokuwa/micronaut/logging/request/CompositeTest.java new file mode 100644 index 0000000..26e766d --- /dev/null +++ b/src/test/java/io/kokuwa/micronaut/logging/request/CompositeTest.java @@ -0,0 +1,41 @@ +package io.kokuwa.micronaut.logging.request; + +import javax.inject.Inject; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import ch.qos.logback.classic.Level; +import io.kokuwa.micronaut.logging.AbstractTest; +import io.micronaut.test.annotation.MicronautTest; + +/** + * Test for MDC and request filter combined. + * + * @author Stephan Schnabel + */ +@DisplayName("request-composite") +@MicronautTest(environments = "test-composite") +public class CompositeTest extends AbstractTest { + + @Inject + TestClient client; + + @DisplayName("default level") + @Test + void defaultLogging() { + client.assertLevel(Level.INFO, client.token("somebody"), null); + } + + @DisplayName("level set by mdc") + @Test + void headerFromMdc() { + client.assertLevel(Level.DEBUG, client.token("horst"), null); + } + + @DisplayName("level set by header (overriding mdc)") + @Test + void headerFromHeader() { + client.assertLevel(Level.TRACE, client.token("horst"), "TRACE"); + } +} diff --git a/src/test/java/io/kokuwa/micronaut/logging/request/RequestHeaderTest.java b/src/test/java/io/kokuwa/micronaut/logging/request/RequestHeaderTest.java new file mode 100644 index 0000000..2b7ee19 --- /dev/null +++ b/src/test/java/io/kokuwa/micronaut/logging/request/RequestHeaderTest.java @@ -0,0 +1,57 @@ +package io.kokuwa.micronaut.logging.request; + +import javax.inject.Inject; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import ch.qos.logback.classic.Level; +import io.kokuwa.micronaut.logging.AbstractTest; + +/** + * Test for {@link HeaderLoggingServerHttpFilter}. + * + * @author Stephan Schnabel + */ +@DisplayName("request-header") +public class RequestHeaderTest extends AbstractTest { + + @Inject + TestClient client; + + @DisplayName("header missing") + @Test + void headerMissing() { + client.assertLevel(Level.INFO, null, null); + } + + @DisplayName("header invalid, use DEBUG as default from logback") + @Test + void headerInvalid() { + client.assertLevel(Level.DEBUG, null, "TRCE"); + } + + @DisplayName("level trace (below default)") + @Test + void headerLevelTrace() { + client.assertLevel(Level.TRACE, null, "TRACE"); + } + + @DisplayName("level debug (below default)") + @Test + void headerLevelDebug() { + client.assertLevel(Level.DEBUG, null, "DEBUG"); + } + + @DisplayName("level info (is default)") + @Test + void headerLevelInfo() { + client.assertLevel(Level.INFO, null, "INFO"); + } + + @DisplayName("level warn (above default)") + @Test + void headerLevelWarn() { + client.assertLevel(Level.INFO, null, "WARN"); + } +} diff --git a/src/test/java/io/kokuwa/micronaut/logging/request/RequestPrincipalTest.java b/src/test/java/io/kokuwa/micronaut/logging/request/RequestPrincipalTest.java new file mode 100644 index 0000000..f8f1fcc --- /dev/null +++ b/src/test/java/io/kokuwa/micronaut/logging/request/RequestPrincipalTest.java @@ -0,0 +1,44 @@ +package io.kokuwa.micronaut.logging.request; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import javax.inject.Inject; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import io.kokuwa.micronaut.logging.AbstractTest; + +/** + * Test for {@link PrincipalHttpFilter}. + * + * @author Stephan Schnabel + */ +@DisplayName("request-principal") +public class RequestPrincipalTest extends AbstractTest { + + @Inject + TestClient client; + + @DisplayName("token missing") + @Test + void tokenMissing() { + assertPrincipal(null, null); + } + + @DisplayName("token invalid") + @Test + void tokenInvalid() { + assertPrincipal(null, "meh"); + } + + @DisplayName("token valid") + @Test + void tokenValid() { + assertPrincipal("meh", client.token("meh")); + } + + private void assertPrincipal(String expectedPrincipal, String actualTokenValue) { + assertEquals(expectedPrincipal, client.get(actualTokenValue, null).getPrincipal()); + } +} diff --git a/src/test/java/io/kokuwa/micronaut/logging/request/TestClient.java b/src/test/java/io/kokuwa/micronaut/logging/request/TestClient.java new file mode 100644 index 0000000..669e907 --- /dev/null +++ b/src/test/java/io/kokuwa/micronaut/logging/request/TestClient.java @@ -0,0 +1,64 @@ +package io.kokuwa.micronaut.logging.request; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jwt.JWTClaimsSet; + +import ch.qos.logback.classic.Level; +import io.kokuwa.micronaut.logging.request.TestController.TestResponse; +import io.micronaut.http.HttpRequest; +import io.micronaut.http.HttpStatus; +import io.micronaut.http.client.HttpClient; +import io.micronaut.http.client.annotation.Client; +import io.micronaut.security.token.jwt.signature.SignatureGeneratorConfiguration; + +/** + * Contoller for testing {@link HeaderLoggingServerHttpFilter} and {@link PrincipalHttpFilter}. + * + * @author Stephan Schnabel + */ +@Singleton +public class TestClient { + + @Inject + @Client("/") + HttpClient client; + @Inject + SignatureGeneratorConfiguration signature; + + String token(String subject) { + try { + return signature.sign(new JWTClaimsSet.Builder().subject(subject).build()).serialize(); + } catch (JOSEException e) { + fail("failed to create token"); + return null; + } + } + + TestResponse get(String token, String header) { + + var request = HttpRequest.GET("/"); + if (token != null) { + request.bearerAuth(token); + } + if (header != null) { + request.getHeaders().add(HeaderLoggingServerHttpFilter.DEFAULT_HEADER, header); + } + + var response = client.toBlocking().exchange(request, TestResponse.class); + assertEquals(HttpStatus.OK, response.getStatus(), "status"); + assertTrue(response.getBody().isPresent(), "body"); + + return response.body(); + } + + void assertLevel(Level expectedLevel, String actualTokenValue, String actualHeaderValue) { + assertEquals(expectedLevel.toString(), get(actualTokenValue, actualHeaderValue).getLevel()); + } +} diff --git a/src/test/java/io/kokuwa/micronaut/logging/request/TestController.java b/src/test/java/io/kokuwa/micronaut/logging/request/TestController.java new file mode 100644 index 0000000..58bdf5b --- /dev/null +++ b/src/test/java/io/kokuwa/micronaut/logging/request/TestController.java @@ -0,0 +1,52 @@ +package io.kokuwa.micronaut.logging.request; + +import org.slf4j.MDC; + +import ch.qos.logback.classic.Level; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.security.annotation.Secured; +import io.micronaut.security.rules.SecurityRule; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * Controller for testing {@link HeaderLoggingServerHttpFilter} and {@link PrincipalHttpFilter}. + * + * @author Stephan Schnabel + */ +@Secured({ SecurityRule.IS_ANONYMOUS, SecurityRule.IS_AUTHENTICATED }) +@Controller +@Slf4j +public class TestController { + + @Get("/") + TestResponse run() { + + var principal = MDC.get(PrincipalHttpFilter.DEFAULT_KEY); + var level = Level.OFF; + if (log.isTraceEnabled()) { + level = Level.TRACE; + } else if (log.isDebugEnabled()) { + level = Level.DEBUG; + } else if (log.isInfoEnabled()) { + level = Level.INFO; + } else if (log.isWarnEnabled()) { + level = Level.WARN; + } else if (log.isErrorEnabled()) { + level = Level.ERROR; + } + + return new TestResponse(level.toString(), principal); + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class TestResponse { + private String level; + private String principal; + } +} diff --git a/src/test/resources/META-INF/build-info.properties b/src/test/resources/META-INF/build-info.properties new file mode 100644 index 0000000..5401a6c --- /dev/null +++ b/src/test/resources/META-INF/build-info.properties @@ -0,0 +1,2 @@ +serviceName: ${project.artifactId} +serviceVersion: ${project.version} diff --git a/src/test/resources/application-test-composite.yaml b/src/test/resources/application-test-composite.yaml new file mode 100644 index 0000000..7ba34db --- /dev/null +++ b/src/test/resources/application-test-composite.yaml @@ -0,0 +1,8 @@ +logger: + mdc: + principal: + level: DEBUG + loggers: + - io.kokuwa + values: + - horst diff --git a/src/test/resources/application-test-mdc.yaml b/src/test/resources/application-test-mdc.yaml index 69cbc89..ef6bfc5 100644 --- a/src/test/resources/application-test-mdc.yaml +++ b/src/test/resources/application-test-mdc.yaml @@ -1,28 +1,26 @@ logger: - levels: - io.micronaut.logging.PropertiesLoggingLevelsConfigurer: "OFF" mdc: key1: key: key level: DEBUG loggers: - - io.kokuwa.a - - io.kokuwa.b + - io.kokuwa.a + - io.kokuwa.b values: - - value-1 - - value-2 + - value-1 + - value-2 key2: key: key level: TRACE loggers: - - io.kokuwa.b - - io.kokuwa.c + - io.kokuwa.b + - io.kokuwa.c values: - - value-2 + - value-2 key: level: TRACE loggers: - - io.kokuwa + - io.kokuwa values: - - value-3 + - value-3 user: {} diff --git a/src/test/resources/application-test.yaml b/src/test/resources/application-test.yaml index 867b23e..42aa67e 100644 --- a/src/test/resources/application-test.yaml +++ b/src/test/resources/application-test.yaml @@ -7,3 +7,10 @@ micronaut: generator: secret: pleaseChangeThisSecretForANewOne jws-algorithm: HS256 + http: + client: + logger-name: io.kokuwa.Test + +logger: + levels: + io.kokuwa.Test: TRACE