├── .all-contributorsrc ├── .github ├── CODEOWNERS ├── dependabot.yml ├── project.yml ├── release │ └── maven-settings.xml.gpg └── workflows │ ├── build.yml │ ├── pre-release.yml │ ├── quarkus-snapshot.yaml │ ├── release-perform.yml │ └── release-prepare.yml ├── .gitignore ├── .idea └── icon.svg ├── LICENSE ├── README.md ├── deployment ├── pom.xml └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── quarkiverse │ │ │ └── loggingmanager │ │ │ └── deployment │ │ │ ├── LoggingManagerBuildItem.java │ │ │ ├── LoggingManagerConfig.java │ │ │ ├── LoggingManagerOpenAPIFilter.java │ │ │ ├── LoggingManagerProcessor.java │ │ │ └── devui │ │ │ └── LoggingManagerDevUIProcessor.java │ └── resources │ │ └── dev-ui │ │ ├── qwc-logging-manager-card.js │ │ └── qwc-logging-manager-loggers.js │ └── test │ └── java │ └── io │ └── quarkiverse │ └── loggingmanager │ └── deployment │ ├── CustomConfigTest.java │ ├── CustomHttpRootTest.java │ ├── ErroneousConfigTest.java │ ├── NoConfigTest.java │ └── devui │ └── StaticDataDevUITest.java ├── docs ├── antora.yml ├── modules │ └── ROOT │ │ ├── assets │ │ └── images │ │ │ ├── .keepme │ │ │ ├── logmanager.svg │ │ │ └── openapi.png │ │ ├── examples │ │ └── .keepme │ │ ├── nav.adoc │ │ └── pages │ │ ├── includes │ │ ├── attributes.adoc │ │ └── quarkus-logging-manager.adoc │ │ └── index.adoc ├── pom.xml └── templates │ └── includes │ └── attributes.adoc ├── openapi.png ├── pom.xml └── runtime ├── pom.xml └── src └── main ├── java └── io │ └── quarkiverse │ └── loggingmanager │ ├── LevelHandler.java │ ├── LogController.java │ ├── LoggerHandler.java │ ├── LoggerManagerRecorder.java │ ├── LoggingManagerNotFoundHandler.java │ ├── LoggingManagerRuntimeConfig.java │ └── devui │ └── LoggingManagerJsonRpcService.java └── resources └── META-INF └── quarkus-extension.yaml /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "oscarfh", 10 | "name": "oscarfh", 11 | "avatar_url": "https://avatars3.githubusercontent.com/u/3311764?v=4", 12 | "profile": "https://github.com/oscarfh", 13 | "contributions": [ 14 | "code", 15 | "maintenance" 16 | ] 17 | }, 18 | { 19 | "login": "phillip-kruger", 20 | "name": "Phillip Krüger", 21 | "avatar_url": "https://avatars3.githubusercontent.com/u/6836179?v=4", 22 | "profile": "http://www.phillip-kruger.com", 23 | "contributions": [ 24 | "code", 25 | "maintenance" 26 | ] 27 | }, 28 | { 29 | "login": "manofthepeace", 30 | "name": "manofthepeace", 31 | "avatar_url": "https://avatars.githubusercontent.com/u/13215031?v=4", 32 | "profile": "https://github.com/manofthepeace", 33 | "contributions": [ 34 | "maintenance", 35 | "code" 36 | ] 37 | }, 38 | { 39 | "login": "spieps", 40 | "name": "Seth Piepergerdes", 41 | "avatar_url": "https://avatars.githubusercontent.com/u/103952931?v=4", 42 | "profile": "https://github.com/spieps", 43 | "contributions": [ 44 | "maintenance", 45 | "code" 46 | ] 47 | }, 48 | { 49 | "login": "ChMThiel", 50 | "name": "Christian Thiel", 51 | "avatar_url": "https://avatars.githubusercontent.com/u/70508469?v=4", 52 | "profile": "https://github.com/ChMThiel", 53 | "contributions": [ 54 | "code" 55 | ] 56 | }, 57 | { 58 | "login": "survivant", 59 | "name": "Sebastien Dionne", 60 | "avatar_url": "https://avatars.githubusercontent.com/u/191879?v=4", 61 | "profile": "https://github.com/survivant", 62 | "contributions": [ 63 | "doc" 64 | ] 65 | }, 66 | { 67 | "login": "Koekebakkert", 68 | "name": "Koekebakkert", 69 | "avatar_url": "https://avatars.githubusercontent.com/u/33450925?v=4", 70 | "profile": "https://github.com/Koekebakkert", 71 | "contributions": [ 72 | "maintenance" 73 | ] 74 | }, 75 | { 76 | "login": "stuartwdouglas", 77 | "name": "Stuart Douglas", 78 | "avatar_url": "https://avatars.githubusercontent.com/u/328571?v=4", 79 | "profile": "https://github.com/stuartwdouglas", 80 | "contributions": [ 81 | "code" 82 | ] 83 | }, 84 | { 85 | "login": "PierreBtz", 86 | "name": "Pierre Beitz", 87 | "avatar_url": "https://avatars.githubusercontent.com/u/9881659?v=4", 88 | "profile": "https://github.com/PierreBtz", 89 | "contributions": [ 90 | "doc" 91 | ] 92 | }, 93 | { 94 | "login": "melloware", 95 | "name": "Melloware", 96 | "avatar_url": "https://avatars.githubusercontent.com/u/4399574?v=4", 97 | "profile": "https://melloware.com", 98 | "contributions": [ 99 | "code", 100 | "maintenance" 101 | ] 102 | }, 103 | { 104 | "login": "gsmet", 105 | "name": "Guillaume Smet", 106 | "avatar_url": "https://avatars.githubusercontent.com/u/1279749?v=4", 107 | "profile": "https://lesincroyableslivres.fr/", 108 | "contributions": [ 109 | "code" 110 | ] 111 | }, 112 | { 113 | "login": "EricWittmann", 114 | "name": "Eric Wittmann", 115 | "avatar_url": "https://avatars.githubusercontent.com/u/1890703?v=4", 116 | "profile": "https://github.com/EricWittmann", 117 | "contributions": [ 118 | "test" 119 | ] 120 | }, 121 | { 122 | "login": "MikeEdgar", 123 | "name": "Michael Edgar", 124 | "avatar_url": "https://avatars.githubusercontent.com/u/20868526?v=4", 125 | "profile": "http://www.xlate.io/", 126 | "contributions": [ 127 | "review" 128 | ] 129 | }, 130 | { 131 | "login": "alex-kovalenko1982", 132 | "name": "Alex Kovalenko", 133 | "avatar_url": "https://avatars.githubusercontent.com/u/69167029?v=4", 134 | "profile": "https://github.com/alex-kovalenko1982", 135 | "contributions": [ 136 | "ideas" 137 | ] 138 | }, 139 | { 140 | "login": "tqvarnst", 141 | "name": "Thomas Qvarnström", 142 | "avatar_url": "https://avatars.githubusercontent.com/u/1204115?v=4", 143 | "profile": "https://github.com/tqvarnst", 144 | "contributions": [ 145 | "ideas" 146 | ] 147 | }, 148 | { 149 | "login": "Ladicek", 150 | "name": "Ladislav Thon", 151 | "avatar_url": "https://avatars.githubusercontent.com/u/480590?v=4", 152 | "profile": "https://github.com/Ladicek", 153 | "contributions": [ 154 | "code" 155 | ] 156 | } 157 | ], 158 | "contributorsPerLine": 7, 159 | "projectName": "quarkus-logging-manager", 160 | "projectOwner": "quarkiverse", 161 | "repoType": "github", 162 | "repoHost": "https://github.com", 163 | "skipCi": true, 164 | "commitType": "docs", 165 | "commitConvention": "angular" 166 | } 167 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # More details are here: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 5 | 6 | # The '*' pattern is global owners. 7 | 8 | # Order is important. The last matching pattern has the most precedence. 9 | # The folders are ordered as follows: 10 | 11 | # In each subsection folders are ordered first by depth, then alphabetically. 12 | # This should make it easy to add new rules without breaking existing ones. 13 | 14 | * @quarkiverse/quarkiverse-logging-manager 15 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "maven" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | ignore: 13 | - dependency-name: "io.quarkus:quarkus-bom" 14 | - dependency-name: "io.quarkus:quarkus-extension-processor" 15 | - dependency-name: "io.quarkus:quarkus-maven-plugin" 16 | - dependency-name: "io.quarkus:quarkus-extension-maven-plugin" 17 | groups: 18 | quarkus: 19 | patterns: 20 | - "io.quarkus*" 21 | - "quarkus*" 22 | quarkiverse: 23 | patterns: 24 | - "io.quarkiverse*" 25 | dependencies: 26 | patterns: 27 | - "*" 28 | exclude-patterns: 29 | - "io.quarkus*" 30 | - "quarkus*" 31 | - "io.quarkiverse*" 32 | - package-ecosystem: "github-actions" 33 | directory: "/" 34 | schedule: 35 | interval: "daily" 36 | -------------------------------------------------------------------------------- /.github/project.yml: -------------------------------------------------------------------------------- 1 | release: 2 | current-version: "3.3.4" 3 | next-version: "999-SNAPSHOT" 4 | -------------------------------------------------------------------------------- /.github/release/maven-settings.xml.gpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quarkiverse/quarkus-logging-manager/1db9875b8e6cc1221ba7b2b1353b6974981c4422/.github/release/maven-settings.xml.gpg -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | paths-ignore: 8 | - '.gitignore' 9 | - 'CODEOWNERS' 10 | - 'LICENSE' 11 | - '*.md' 12 | - '*.adoc' 13 | - '*.txt' 14 | - '.all-contributorsrc' 15 | pull_request: 16 | paths-ignore: 17 | - '.gitignore' 18 | - 'CODEOWNERS' 19 | - 'LICENSE' 20 | - '*.md' 21 | - '*.adoc' 22 | - '*.txt' 23 | - '.all-contributorsrc' 24 | 25 | concurrency: 26 | group: ${{ github.workflow }}-${{ github.ref }} 27 | cancel-in-progress: true 28 | 29 | defaults: 30 | run: 31 | shell: bash 32 | 33 | jobs: 34 | build: 35 | name: Build on ${{ matrix.os }} 36 | strategy: 37 | fail-fast: false 38 | matrix: 39 | # os: [windows-latest, macos-latest, ubuntu-latest] 40 | os: [ubuntu-latest] 41 | runs-on: ${{ matrix.os }} 42 | steps: 43 | - name: Prepare git 44 | run: git config --global core.autocrlf false 45 | if: startsWith(matrix.os, 'windows') 46 | 47 | - uses: actions/checkout@v4 48 | - name: Set up JDK 17 49 | uses: actions/setup-java@v4 50 | with: 51 | distribution: temurin 52 | java-version: 17 53 | cache: 'maven' 54 | 55 | - name: Build with Maven 56 | run: mvn -B clean install -Dno-format 57 | 58 | - name: Build with Maven (Native) 59 | run: mvn -B install -Dnative -Dquarkus.native.container-build -Dnative.surefire.skip 60 | -------------------------------------------------------------------------------- /.github/workflows/pre-release.yml: -------------------------------------------------------------------------------- 1 | name: Quarkiverse Pre Release 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '.github/project.yml' 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | pre-release: 14 | name: Pre-Release 15 | uses: quarkiverse/.github/.github/workflows/pre-release.yml@main 16 | secrets: inherit 17 | -------------------------------------------------------------------------------- /.github/workflows/quarkus-snapshot.yaml: -------------------------------------------------------------------------------- 1 | name: "Quarkus ecosystem CI" 2 | on: 3 | workflow_dispatch: 4 | watch: 5 | types: [started] 6 | 7 | # For this CI to work, ECOSYSTEM_CI_TOKEN needs to contain a GitHub with rights to close the Quarkus issue that the user/bot has opened, 8 | # while 'ECOSYSTEM_CI_REPO_PATH' needs to be set to the corresponding path in the 'quarkusio/quarkus-ecosystem-ci' repository 9 | 10 | env: 11 | ECOSYSTEM_CI_REPO: quarkusio/quarkus-ecosystem-ci 12 | ECOSYSTEM_CI_REPO_FILE: context.yaml 13 | JAVA_VERSION: 17 14 | 15 | ######################### 16 | # Repo specific setting # 17 | ######################### 18 | 19 | ECOSYSTEM_CI_REPO_PATH: quarkiverse-logging-manager 20 | 21 | concurrency: 22 | group: ${{ github.workflow }}-${{ github.ref }} 23 | cancel-in-progress: true 24 | 25 | defaults: 26 | run: 27 | shell: bash 28 | 29 | jobs: 30 | build: 31 | name: "Build against latest Quarkus snapshot" 32 | runs-on: ubuntu-latest 33 | # Allow to manually launch the ecosystem CI in addition to the bots 34 | if: github.actor == 'quarkusbot' || github.actor == 'quarkiversebot' || github.actor == '' 35 | 36 | steps: 37 | - name: Install yq 38 | uses: dcarbone/install-yq-action@v1.3.1 39 | 40 | - name: Set up Java 41 | uses: actions/setup-java@v4 42 | with: 43 | distribution: temurin 44 | java-version: ${{ env.JAVA_VERSION }} 45 | 46 | - name: Checkout repo 47 | uses: actions/checkout@v4 48 | with: 49 | path: current-repo 50 | 51 | - name: Checkout Ecosystem 52 | uses: actions/checkout@v4 53 | with: 54 | repository: ${{ env.ECOSYSTEM_CI_REPO }} 55 | path: ecosystem-ci 56 | 57 | - name: Setup and Run Tests 58 | run: ./ecosystem-ci/setup-and-test 59 | env: 60 | ECOSYSTEM_CI_TOKEN: ${{ secrets.ECOSYSTEM_CI_TOKEN }} 61 | -------------------------------------------------------------------------------- /.github/workflows/release-perform.yml: -------------------------------------------------------------------------------- 1 | name: Quarkiverse Perform Release 2 | run-name: Perform ${{github.event.inputs.tag || github.ref_name}} Release 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | workflow_dispatch: 8 | inputs: 9 | tag: 10 | description: 'Tag to release' 11 | required: true 12 | 13 | permissions: 14 | attestations: write 15 | id-token: write 16 | contents: read 17 | 18 | concurrency: 19 | group: ${{ github.workflow }}-${{ github.ref }} 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | perform-release: 24 | name: Perform Release 25 | uses: quarkiverse/.github/.github/workflows/perform-release.yml@main 26 | secrets: inherit 27 | with: 28 | version: ${{github.event.inputs.tag || github.ref_name}} 29 | -------------------------------------------------------------------------------- /.github/workflows/release-prepare.yml: -------------------------------------------------------------------------------- 1 | name: Quarkiverse Prepare Release 2 | 3 | on: 4 | pull_request: 5 | types: [ closed ] 6 | paths: 7 | - '.github/project.yml' 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | prepare-release: 15 | name: Prepare Release 16 | if: ${{ github.event.pull_request.merged == true}} 17 | uses: quarkiverse/.github/.github/workflows/prepare-release.yml@main 18 | secrets: inherit 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # Eclipse 26 | .project 27 | .classpath 28 | .settings/ 29 | bin/ 30 | 31 | # IntelliJ 32 | .idea 33 | *.ipr 34 | *.iml 35 | *.iws 36 | 37 | # NetBeans 38 | nb-configuration.xml 39 | 40 | # Visual Studio Code 41 | .vscode 42 | .factorypath 43 | 44 | # OSX 45 | .DS_Store 46 | 47 | # Vim 48 | *.swp 49 | *.swo 50 | 51 | # patch 52 | *.orig 53 | *.rej 54 | 55 | # Gradle 56 | .gradle/ 57 | build/ 58 | 59 | # Maven 60 | target/ 61 | pom.xml.tag 62 | pom.xml.releaseBackup 63 | pom.xml.versionsBackup 64 | release.properties 65 | -------------------------------------------------------------------------------- /.idea/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 20 | 23 | 65 | 67 | 69 | 71 | 72 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | # Logging Manager 6 |
7 |
8 | 9 | [![Maven Central](https://img.shields.io/maven-central/v/io.quarkiverse.loggingmanager/quarkus-logging-manager?color=cool-green&style=flat-square)](https://mvnrepository.com/artifact/io.quarkiverse.loggingmanager/quarkus-logging-manager) 10 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=flat-square)](https://opensource.org/licenses/Apache-2.0) 11 | [![Build](https://github.com/quarkiverse/quarkus-logging-manager/actions/workflows/build.yml/badge.svg)](https://github.com/quarkiverse/quarkus-logging-manager/actions/workflows/build.yml) 12 | 13 | The **Quarkus Logging Manager** Extension provides you endpoints to visualize and manage the 14 | log level of your loggers. 15 | 16 | | Endpoint | Http Method | Description | 17 | |----------------------------------------------|:-----------:|:----------------------------------------------------------------------------------------------------:| 18 | | `/q/logging-manager` | `GET` | Returns the list of all loggers, with information about the configured and effective level | 19 | | `/q/logging-manager?loggerName={loggerName}` | `GET` | Returns the logger specified by this name, with information about the configured and effective level | 20 | | `/q/logging-manager` | `POST` | Changes the log level of the specified logger | 21 | | `/q/logging-manager/levels` | `GET` | Get all the available level | 22 | 23 | ## Security 24 | Security of endpoints is important, and we do not want to allow unknown people to know (or worse, change!) the log levels of 25 | our applications. 26 | Fortunately we can secure our endpoints using Quarkus' default security mechanism, as described in [Security Overview](https://quarkus.io/guides/security-overview). 27 | All you have to do is define your application.properties similar to this: 28 | 29 | ```properties 30 | quarkus.http.auth.basic=true # If you want basic auth. Multiple auth mechanism are supported 31 | 32 | quarkus.http.auth.policy.admin-access.roles-allowed=admin 33 | quarkus.http.auth.permission.roles1.paths=/q/logging-manager 34 | quarkus.http.auth.permission.roles1.policy=admin-access 35 | ``` 36 | And, in case you chose Basic Auth, provide a IdentityProvider (either by implementing one or adding an extension that provides 37 | one). 38 | Quarkus will take care of matching the paths (in this case `/q/logging-manager` to the policy you defined and 39 | granting or denying access). 40 | Then you can also secure all the endpoints in your application using this configuration. 41 | 42 | 43 | ## Example: 44 | 45 | To use this in your application, simply add this in your pom.xml: 46 | 47 | ```xml 48 | 49 | io.quarkiverse.loggingmanager 50 | quarkus-logging-manager 51 | ${logger-manager.version} 52 | runtime 53 | 54 | ``` 55 | 56 | Note: Replace `${logger-manager.version}` with the latest version 57 | 58 | ## OpenAPI 59 | 60 | You can include the Logger Manager API in the OpenAPI document (and thus also Swagger UI). This needs to be 61 | enabled via config: 62 | 63 | ``` 64 | quarkus.logging-manager.openapi.included=true 65 | ``` 66 | 67 | This will then add the following to your OpenAPI: 68 | 69 | ![swagger_manager screenshot](openapi.png "Swagger UI Screenshot") 70 | 71 | ## Roadmap 72 | - [x] OpenApiSpec for the endpoints 73 | - [x] Make endpoint configurable 74 | - [x] Enable customizable security on the endpoint (see readme file) 75 | 76 | ## Contributors ✨ 77 | 78 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 |
oscarfh
oscarfh

💻 🚧
Phillip Krüger
Phillip Krüger

💻 🚧
manofthepeace
manofthepeace

🚧 💻
Seth Piepergerdes
Seth Piepergerdes

🚧 💻
Christian Thiel
Christian Thiel

💻
Sebastien Dionne
Sebastien Dionne

📖
Koekebakkert
Koekebakkert

🚧
Stuart Douglas
Stuart Douglas

💻
Pierre Beitz
Pierre Beitz

📖
Melloware
Melloware

💻 🚧
Guillaume Smet
Guillaume Smet

💻
Eric Wittmann
Eric Wittmann

⚠️
Michael Edgar
Michael Edgar

👀
Alex Kovalenko
Alex Kovalenko

🤔
Thomas Qvarnström
Thomas Qvarnström

🤔
Ladislav Thon
Ladislav Thon

💻
109 | 110 | 111 | 112 | 113 | 114 | 115 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 116 | 117 | [1]: https://quarkus.io/guides/security-authorization -------------------------------------------------------------------------------- /deployment/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | io.quarkiverse.loggingmanager 6 | quarkus-logging-manager-parent 7 | 999-SNAPSHOT 8 | ../pom.xml 9 | 10 | 11 | quarkus-logging-manager-deployment 12 | Quarkus - Logging Manager - Deployment 13 | 14 | 15 | 3.5.3 16 | 17 | 18 | 19 | 20 | io.quarkus 21 | quarkus-core-deployment 22 | 23 | 24 | 25 | ${project.groupId} 26 | quarkus-logging-manager 27 | ${project.version} 28 | 29 | 30 | 31 | io.quarkus 32 | quarkus-vertx-http-deployment 33 | 34 | 35 | 36 | io.quarkus 37 | quarkus-smallrye-openapi-spi 38 | 39 | 40 | 41 | io.quarkus 42 | quarkus-junit5-internal 43 | test 44 | 45 | 46 | 47 | io.quarkus 48 | quarkus-vertx-http-dev-ui-tests 49 | test 50 | 51 | 52 | 53 | io.rest-assured 54 | rest-assured 55 | test 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.apache.maven.plugins 63 | maven-compiler-plugin 64 | 65 | 66 | 67 | io.quarkus 68 | quarkus-extension-processor 69 | ${quarkus.version} 70 | 71 | 72 | 73 | 74 | 75 | 76 | org.apache.maven.plugins 77 | maven-surefire-plugin 78 | ${maven.surefire.version} 79 | 80 | 81 | org.jboss.logmanager.LogManager 82 | ${maven.home} 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /deployment/src/main/java/io/quarkiverse/loggingmanager/deployment/LoggingManagerBuildItem.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager.deployment; 2 | 3 | import io.quarkus.builder.item.SimpleBuildItem; 4 | 5 | final class LoggingManagerBuildItem extends SimpleBuildItem { 6 | 7 | private final String loggingManagerFinalDestination; 8 | private final String loggingManagerPath; 9 | 10 | public LoggingManagerBuildItem(String loggingManagerFinalDestination, String loggingManagerPath) { 11 | this.loggingManagerFinalDestination = loggingManagerFinalDestination; 12 | this.loggingManagerPath = loggingManagerPath; 13 | } 14 | 15 | public String getLoggingManagerFinalDestination() { 16 | return loggingManagerFinalDestination; 17 | } 18 | 19 | public String getLoggingManagerPath() { 20 | return loggingManagerPath; 21 | } 22 | } -------------------------------------------------------------------------------- /deployment/src/main/java/io/quarkiverse/loggingmanager/deployment/LoggingManagerConfig.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager.deployment; 2 | 3 | import io.quarkus.runtime.annotations.ConfigPhase; 4 | import io.quarkus.runtime.annotations.ConfigRoot; 5 | import io.smallrye.config.ConfigMapping; 6 | import io.smallrye.config.WithDefault; 7 | import io.smallrye.config.WithName; 8 | 9 | @ConfigMapping(prefix = "quarkus.logging-manager") 10 | @ConfigRoot(phase = ConfigPhase.BUILD_TIME) 11 | public interface LoggingManagerConfig { 12 | 13 | /** 14 | * The base path 15 | */ 16 | @WithDefault("logging-manager") 17 | String basePath(); 18 | 19 | /** 20 | * Whether to include the Logger Manager endpoints in the generated OpenAPI document 21 | */ 22 | @WithName("openapi.included") 23 | @WithDefault("false") 24 | boolean openapiIncluded(); 25 | 26 | /** 27 | * The tag to use if OpenAPI is included 28 | */ 29 | @WithDefault("Logging Manager") 30 | String openapiTag(); 31 | 32 | /** 33 | * Always include this. By default, this will always be included. 34 | * Setting this to false will also exclude this in Prod 35 | */ 36 | @WithDefault("true") 37 | boolean alwaysInclude(); 38 | } -------------------------------------------------------------------------------- /deployment/src/main/java/io/quarkiverse/loggingmanager/deployment/LoggingManagerOpenAPIFilter.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager.deployment; 2 | 3 | import java.util.Collections; 4 | import java.util.LinkedHashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import org.eclipse.microprofile.openapi.OASFactory; 9 | import org.eclipse.microprofile.openapi.OASFilter; 10 | import org.eclipse.microprofile.openapi.models.OpenAPI; 11 | import org.eclipse.microprofile.openapi.models.Operation; 12 | import org.eclipse.microprofile.openapi.models.PathItem; 13 | import org.eclipse.microprofile.openapi.models.media.Schema; 14 | import org.eclipse.microprofile.openapi.models.parameters.Parameter; 15 | import org.eclipse.microprofile.openapi.models.tags.Tag; 16 | 17 | import io.quarkiverse.loggingmanager.LogController; 18 | 19 | /** 20 | * Create OpenAPI entries (if configured) 21 | */ 22 | public class LoggingManagerOpenAPIFilter implements OASFilter { 23 | 24 | private static final String JSON_CONTENT_TYPE = "application/json"; 25 | private static final String FORM_CONTENT_TYPE = "application/x-www-form-urlencoded"; 26 | 27 | private static final String REF_LOGGER_LEVEL = "#/components/schemas/LoggerLevel"; 28 | private static final String REF_LOGGER_INFO = "#/components/schemas/LoggerInfo"; 29 | 30 | private final String basePath; 31 | private final String tag; 32 | 33 | public LoggingManagerOpenAPIFilter(String basePath, String tag) { 34 | this.basePath = basePath; 35 | this.tag = tag; 36 | } 37 | 38 | @Override 39 | public void filterOpenAPI(OpenAPI openAPI) { 40 | if (openAPI.getComponents() == null) { 41 | openAPI.setComponents(OASFactory.createComponents()); 42 | } 43 | openAPI.getComponents() 44 | .addSchema("LoggerLevel", createLoggerLevel()) 45 | .addSchema("LoggerInfo", createLoggerInfo()); 46 | if (openAPI.getPaths() == null) { 47 | openAPI.setPaths(OASFactory.createPaths()); 48 | } 49 | Tag tag = OASFactory.createTag(); 50 | tag.setName(this.tag); 51 | tag.setDescription("Visualize and manage the log level of your loggers."); 52 | openAPI.addTag(tag); 53 | openAPI.getPaths() 54 | .addPathItem(basePath, createLoggersPathItem()) 55 | .addPathItem(basePath + "/levels", createLevelsPathItem()); 56 | } 57 | 58 | private Schema createLoggerLevel() { 59 | Schema schema = OASFactory.createSchema() 60 | .title("LoggerLevel") 61 | .type(List.of(Schema.SchemaType.STRING)); 62 | LogController.LEVELS.forEach(schema::addEnumeration); 63 | return schema; 64 | } 65 | 66 | private Schema createLoggerInfo() { 67 | Map properties = new LinkedHashMap<>(); 68 | properties.put("configuredLevel", OASFactory.createSchema().ref(REF_LOGGER_LEVEL)); 69 | properties.put("effectiveLevel", OASFactory.createSchema().ref(REF_LOGGER_LEVEL)); 70 | properties.put("name", OASFactory.createSchema().type(List.of(Schema.SchemaType.STRING))); 71 | return OASFactory.createSchema() 72 | .title("LoggerInfo") 73 | .type(List.of(Schema.SchemaType.OBJECT)) 74 | .properties(properties); 75 | } 76 | 77 | private PathItem createLoggersPathItem() { 78 | return OASFactory.createPathItem() 79 | .summary("Return info on all loggers, or a specific logger") 80 | .description("Logging Manager Loggers") 81 | .GET(createLoggersGetOperation()) 82 | .POST(createLoggerPostOperation()); 83 | } 84 | 85 | private Operation createLoggersGetOperation() { 86 | return OASFactory.createOperation() 87 | .operationId("logging_manager_get_all") 88 | .summary("Information on Logger(s)") 89 | .description("Get information on all loggers or a specific logger.") 90 | .tags(Collections.singletonList(tag)) 91 | .addParameter(OASFactory.createParameter() 92 | .name("loggerName").in(Parameter.In.QUERY) 93 | .schema(OASFactory.createSchema().type(List.of(Schema.SchemaType.STRING)))) 94 | .responses(OASFactory.createAPIResponses() 95 | .addAPIResponse("200", OASFactory.createAPIResponse() 96 | .description("Ok") 97 | .content(OASFactory.createContent().addMediaType( 98 | JSON_CONTENT_TYPE, 99 | OASFactory.createMediaType().schema(OASFactory.createSchema() 100 | .type(List.of(Schema.SchemaType.ARRAY)) 101 | .items(OASFactory.createSchema().ref(REF_LOGGER_INFO)))))) 102 | .addAPIResponse("404", OASFactory.createAPIResponse().description("Not Found"))); 103 | } 104 | 105 | private Operation createLoggerPostOperation() { 106 | Map properties = new LinkedHashMap<>(); 107 | properties.put("loggerName", OASFactory.createSchema()); 108 | properties.put("loggerLevel", OASFactory.createSchema().ref(REF_LOGGER_LEVEL)); 109 | return OASFactory.createOperation() 110 | .operationId("logging_manager_update") 111 | .summary("Update log level") 112 | .description("Update a log level for a certain logger") 113 | .tags(Collections.singletonList(tag)) 114 | .requestBody(OASFactory.createRequestBody() 115 | .content(OASFactory.createContent().addMediaType( 116 | FORM_CONTENT_TYPE, 117 | OASFactory.createMediaType().schema(OASFactory.createSchema() 118 | .type(List.of(Schema.SchemaType.OBJECT)) 119 | .properties(properties))))) 120 | .responses(OASFactory.createAPIResponses() 121 | .addAPIResponse("201", OASFactory.createAPIResponse().description("Created"))); 122 | } 123 | 124 | private PathItem createLevelsPathItem() { 125 | return OASFactory.createPathItem() 126 | .description("All available levels") 127 | .summary("Return all levels that is available") 128 | .GET(OASFactory.createOperation() 129 | .description("This returns all possible log levels") 130 | .operationId("logging_manager_levels") 131 | .tags(Collections.singletonList(tag)) 132 | .summary("Get all available levels") 133 | .responses(OASFactory.createAPIResponses() 134 | .addAPIResponse("200", OASFactory.createAPIResponse() 135 | .description("Ok") 136 | .content(OASFactory.createContent().addMediaType( 137 | JSON_CONTENT_TYPE, 138 | OASFactory.createMediaType().schema(OASFactory.createSchema() 139 | .type(List.of(Schema.SchemaType.ARRAY)) 140 | .items(OASFactory.createSchema().ref(REF_LOGGER_LEVEL)))))))); 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /deployment/src/main/java/io/quarkiverse/loggingmanager/deployment/LoggingManagerProcessor.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager.deployment; 2 | 3 | import java.util.function.BooleanSupplier; 4 | 5 | import io.quarkiverse.loggingmanager.LoggerManagerRecorder; 6 | import io.quarkiverse.loggingmanager.LoggingManagerRuntimeConfig; 7 | import io.quarkus.deployment.Capabilities; 8 | import io.quarkus.deployment.Capability; 9 | import io.quarkus.deployment.annotations.BuildProducer; 10 | import io.quarkus.deployment.annotations.BuildStep; 11 | import io.quarkus.deployment.annotations.ExecutionTime; 12 | import io.quarkus.deployment.annotations.Record; 13 | import io.quarkus.deployment.builditem.FeatureBuildItem; 14 | import io.quarkus.deployment.builditem.LaunchModeBuildItem; 15 | import io.quarkus.runtime.configuration.ConfigurationException; 16 | import io.quarkus.smallrye.openapi.deployment.spi.AddToOpenAPIDefinitionBuildItem; 17 | import io.quarkus.vertx.http.deployment.BodyHandlerBuildItem; 18 | import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem; 19 | import io.quarkus.vertx.http.deployment.RouteBuildItem; 20 | import io.vertx.core.Handler; 21 | import io.vertx.ext.web.RoutingContext; 22 | 23 | class LoggingManagerProcessor { 24 | private static final String FEATURE = "logging-manager"; 25 | 26 | static class OpenAPIIncluded implements BooleanSupplier { 27 | LoggingManagerConfig config; 28 | 29 | public boolean getAsBoolean() { 30 | return config.openapiIncluded(); 31 | } 32 | } 33 | 34 | @BuildStep 35 | FeatureBuildItem feature() { 36 | return new FeatureBuildItem(FEATURE); 37 | } 38 | 39 | @Record(ExecutionTime.RUNTIME_INIT) 40 | @BuildStep 41 | void includeRestEndpoints(BuildProducer routeProducer, 42 | NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem, 43 | LoggingManagerConfig loggingManagerConfig, 44 | BodyHandlerBuildItem bodyHandlerBuildItem, 45 | LoggerManagerRecorder recorder, 46 | LaunchModeBuildItem launchMode, 47 | LoggingManagerRuntimeConfig runtimeConfig) { 48 | 49 | if ("/".equals(loggingManagerConfig.basePath())) { 50 | throw new ConfigurationException( 51 | "quarkus.logging-manager.base-path was set to \"/\", this is not allowed as it blocks the application from serving anything else."); 52 | } 53 | 54 | if (shouldInclude(launchMode, loggingManagerConfig)) { 55 | Handler loggerHandler = recorder.loggerHandler(); 56 | Handler levelHandler = recorder.levelHandler(); 57 | 58 | routeProducer.produce(nonApplicationRootPathBuildItem.routeBuilder() 59 | .management() 60 | .routeFunction(loggingManagerConfig.basePath(), 61 | recorder.routeConsumer(bodyHandlerBuildItem.getHandler(), runtimeConfig)) 62 | .displayOnNotFoundPage("LogManager All available loggers") 63 | .handler(loggerHandler) 64 | .build()); 65 | 66 | routeProducer.produce(nonApplicationRootPathBuildItem.routeBuilder() 67 | .management() 68 | .nestedRoute(loggingManagerConfig.basePath(), "levels") 69 | .displayOnNotFoundPage("LogManager All available log levels") 70 | .handler(levelHandler) 71 | .build()); 72 | } 73 | } 74 | 75 | @BuildStep(onlyIf = OpenAPIIncluded.class) 76 | public void includeInOpenAPIEndpoint(BuildProducer openAPIProducer, 77 | NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem, 78 | Capabilities capabilities, 79 | LaunchModeBuildItem launchMode, 80 | LoggingManagerConfig loggingManagerConfig) { 81 | 82 | // Add to OpenAPI if OpenAPI is available 83 | if (capabilities.isPresent(Capability.SMALLRYE_OPENAPI) 84 | && shouldIncludeInOpenAPI(launchMode, loggingManagerConfig)) { 85 | LoggingManagerOpenAPIFilter filter = new LoggingManagerOpenAPIFilter( 86 | nonApplicationRootPathBuildItem.resolvePath(loggingManagerConfig.basePath()), 87 | loggingManagerConfig.openapiTag()); 88 | openAPIProducer.produce(new AddToOpenAPIDefinitionBuildItem(filter)); 89 | } 90 | } 91 | 92 | private static boolean shouldInclude(LaunchModeBuildItem launchMode, LoggingManagerConfig loggingManagerConfig) { 93 | return launchMode.getLaunchMode().isDevOrTest() || loggingManagerConfig.alwaysInclude(); 94 | } 95 | 96 | private static boolean shouldIncludeInOpenAPI(LaunchModeBuildItem launchMode, LoggingManagerConfig loggingManagerConfig) { 97 | return shouldInclude(launchMode, loggingManagerConfig); 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /deployment/src/main/java/io/quarkiverse/loggingmanager/deployment/devui/LoggingManagerDevUIProcessor.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager.deployment.devui; 2 | 3 | import java.util.Map; 4 | import java.util.stream.Collectors; 5 | 6 | import io.quarkiverse.loggingmanager.LogController; 7 | import io.quarkiverse.loggingmanager.devui.LoggingManagerJsonRpcService; 8 | import io.quarkus.deployment.IsDevelopment; 9 | import io.quarkus.deployment.annotations.BuildProducer; 10 | import io.quarkus.deployment.annotations.BuildStep; 11 | import io.quarkus.devui.spi.JsonRPCProvidersBuildItem; 12 | import io.quarkus.devui.spi.page.CardPageBuildItem; 13 | import io.quarkus.devui.spi.page.Page; 14 | 15 | public class LoggingManagerDevUIProcessor { 16 | private static final String LEVEL = "level"; 17 | 18 | @BuildStep(onlyIf = IsDevelopment.class) 19 | public void pages(BuildProducer cardPageBuildItemBuildProducer) { 20 | CardPageBuildItem card = new CardPageBuildItem(); 21 | 22 | card.addBuildTimeData(LEVEL, LogController.LEVELS 23 | .stream().map((level) -> Map.of(LEVEL, level)) 24 | .collect(Collectors.toList())); 25 | 26 | card.addPage(Page.tableDataPageBuilder("Level") 27 | .showColumn(LEVEL) 28 | .buildTimeDataKey(LEVEL) 29 | .icon("font-awesome-solid:layer-group")); 30 | 31 | card.addPage(Page.webComponentPageBuilder() 32 | .icon("font-awesome-solid:play") 33 | .componentLink("qwc-logging-manager-loggers.js")); 34 | 35 | card.setCustomCard("qwc-logging-manager-card.js"); 36 | cardPageBuildItemBuildProducer.produce(card); 37 | } 38 | 39 | @BuildStep 40 | JsonRPCProvidersBuildItem createJsonRPCService() { 41 | return new JsonRPCProvidersBuildItem(LoggingManagerJsonRpcService.class); 42 | } 43 | } -------------------------------------------------------------------------------- /deployment/src/main/resources/dev-ui/qwc-logging-manager-card.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, css} from 'lit'; 2 | import { pages } from 'build-time-data'; 3 | import 'qwc/qwc-extension-link.js'; 4 | 5 | const NAME = "Logging Manager"; 6 | export class QwcLoggingManagerCard extends LitElement { 7 | 8 | static styles = css` 9 | .identity { 10 | display: flex; 11 | justify-content: flex-start; 12 | } 13 | 14 | .description { 15 | padding-bottom: 10px; 16 | } 17 | 18 | .logo { 19 | padding-bottom: 10px; 20 | margin-right: 5px; 21 | } 22 | 23 | .card-content { 24 | color: var(--lumo-contrast-90pct); 25 | display: flex; 26 | flex-direction: column; 27 | justify-content: flex-start; 28 | padding: 2px 2px; 29 | height: 100%; 30 | } 31 | 32 | .card-content slot { 33 | display: flex; 34 | flex-flow: column wrap; 35 | padding-top: 5px; 36 | } 37 | `; 38 | 39 | static properties = { 40 | description: {type: String} 41 | }; 42 | 43 | constructor() { 44 | super(); 45 | } 46 | 47 | connectedCallback() { 48 | super.connectedCallback(); 49 | } 50 | 51 | render() { 52 | return html`
53 |
54 | 61 |
${this.description}
62 |
63 | ${this._renderCardLinks()} 64 |
65 | `; 66 | } 67 | 68 | _renderCardLinks(){ 69 | return html`${pages.map(page => html` 70 | 81 | 82 | `)}`; 83 | } 84 | 85 | } 86 | customElements.define('qwc-logging-manager-card', QwcLoggingManagerCard); -------------------------------------------------------------------------------- /deployment/src/main/resources/dev-ui/qwc-logging-manager-loggers.js: -------------------------------------------------------------------------------- 1 | import '@vaadin/grid'; 2 | import '@vaadin/grid/vaadin-grid-sort-column.js'; 3 | import '@vaadin/vertical-layout'; 4 | import '@vaadin/icon'; 5 | import '@vaadin/icons'; 6 | import { LitElement, html, css} from 'lit'; 7 | import { JsonRpc } from 'jsonrpc'; 8 | 9 | export class QwcLoggingManagerLoggers extends LitElement { 10 | jsonRpc = new JsonRpc(this); 11 | static styles = css` 12 | .datatable { 13 | height: 100%; 14 | } 15 | .ml-10 { 16 | margin-left: 10px; 17 | } 18 | ` 19 | 20 | static properties = { 21 | _loggers: { state: true }, 22 | _filteredLoggers: { state: true } 23 | } 24 | 25 | constructor() { 26 | super(); 27 | } 28 | 29 | connectedCallback() { 30 | super.connectedCallback(); 31 | this._refreshLoggers(); 32 | } 33 | 34 | disconnectedCallback() { 35 | super.disconnectedCallback(); 36 | } 37 | 38 | _refreshLoggers() { 39 | this.jsonRpc.getLoggers().then(jsonRpcResponse => { 40 | this._resetLoggers(jsonRpcResponse.result); 41 | }); 42 | } 43 | 44 | _resetLoggers(result) { 45 | this._loggers = result; 46 | this._filteredLoggers = result; 47 | } 48 | 49 | render() { 50 | return html` 51 | 69 | 70 | 71 | 72 | 76 | 77 | 78 | 82 | 83 | 84 | 88 | 89 | 90 | ` 91 | } 92 | } 93 | customElements.define('qwc-logging-manager-loggers', QwcLoggingManagerLoggers); -------------------------------------------------------------------------------- /deployment/src/test/java/io/quarkiverse/loggingmanager/deployment/CustomConfigTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager.deployment; 2 | 3 | import org.jboss.shrinkwrap.api.ShrinkWrap; 4 | import org.jboss.shrinkwrap.api.asset.StringAsset; 5 | import org.jboss.shrinkwrap.api.spec.JavaArchive; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.RegisterExtension; 8 | 9 | import io.quarkus.test.QuarkusUnitTest; 10 | import io.restassured.RestAssured; 11 | 12 | public class CustomConfigTest { 13 | 14 | @RegisterExtension 15 | static final QuarkusUnitTest config = new QuarkusUnitTest() 16 | .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) 17 | .addAsResource(new StringAsset("quarkus.logging-manager.base-path=custom"), "application.properties")); 18 | 19 | @Test 20 | public void shouldUseCustomConfig() { 21 | RestAssured.when().get("/q/custom").then().statusCode(200); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /deployment/src/test/java/io/quarkiverse/loggingmanager/deployment/CustomHttpRootTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager.deployment; 2 | 3 | import org.jboss.shrinkwrap.api.ShrinkWrap; 4 | import org.jboss.shrinkwrap.api.asset.StringAsset; 5 | import org.jboss.shrinkwrap.api.spec.JavaArchive; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.RegisterExtension; 8 | 9 | import io.quarkus.test.QuarkusUnitTest; 10 | import io.restassured.RestAssured; 11 | 12 | public class CustomHttpRootTest { 13 | 14 | @RegisterExtension 15 | static final QuarkusUnitTest config = new QuarkusUnitTest() 16 | .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) 17 | .addAsResource(new StringAsset("quarkus.http.root-path=/foo"), "application.properties")); 18 | 19 | @Test 20 | public void shouldUseCustomConfig() { 21 | RestAssured.when().get("/q/logging-manager").then().statusCode(200); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /deployment/src/test/java/io/quarkiverse/loggingmanager/deployment/ErroneousConfigTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager.deployment; 2 | 3 | import org.jboss.shrinkwrap.api.ShrinkWrap; 4 | import org.jboss.shrinkwrap.api.asset.StringAsset; 5 | import org.jboss.shrinkwrap.api.spec.JavaArchive; 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.Test; 8 | import org.junit.jupiter.api.extension.RegisterExtension; 9 | 10 | import io.quarkus.runtime.configuration.ConfigurationException; 11 | import io.quarkus.test.QuarkusUnitTest; 12 | 13 | public class ErroneousConfigTest { 14 | 15 | @RegisterExtension 16 | static final QuarkusUnitTest config = new QuarkusUnitTest() 17 | .setExpectedException(ConfigurationException.class) 18 | .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) 19 | .addAsResource(new StringAsset("quarkus.logging-manager.base-path=/\n"), "application.properties")); 20 | 21 | @Test 22 | public void shouldNotStartApplicationIfPathIsASlash() { 23 | Assertions.fail(); 24 | } 25 | } -------------------------------------------------------------------------------- /deployment/src/test/java/io/quarkiverse/loggingmanager/deployment/NoConfigTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager.deployment; 2 | 3 | import org.jboss.shrinkwrap.api.ShrinkWrap; 4 | import org.jboss.shrinkwrap.api.spec.JavaArchive; 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.RegisterExtension; 7 | 8 | import io.quarkus.test.QuarkusUnitTest; 9 | import io.restassured.RestAssured; 10 | 11 | public class NoConfigTest { 12 | 13 | @RegisterExtension 14 | static final QuarkusUnitTest config = new QuarkusUnitTest() 15 | .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)); 16 | 17 | @Test 18 | public void shouldUseDefaultConfig() { 19 | RestAssured.when().get("/q/logging-manager").then().statusCode(200); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /deployment/src/test/java/io/quarkiverse/loggingmanager/deployment/devui/StaticDataDevUITest.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager.deployment.devui; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | import org.junit.jupiter.api.extension.RegisterExtension; 6 | 7 | import com.fasterxml.jackson.databind.JsonNode; 8 | import com.fasterxml.jackson.databind.node.ArrayNode; 9 | 10 | import io.quarkiverse.loggingmanager.LogController; 11 | import io.quarkus.devui.tests.DevUIBuildTimeDataTest; 12 | import io.quarkus.test.QuarkusDevModeTest; 13 | 14 | public class StaticDataDevUITest extends DevUIBuildTimeDataTest { 15 | 16 | @RegisterExtension 17 | static final QuarkusDevModeTest config = new QuarkusDevModeTest().withEmptyApplication(); 18 | 19 | public StaticDataDevUITest() { 20 | super("io.quarkiverse.loggingmanager.quarkus-logging-manager"); 21 | } 22 | 23 | @Test 24 | public void levelDataAvailable() throws Exception { 25 | JsonNode levelResponse = super.getBuildTimeData("level"); 26 | Assertions.assertAll( 27 | () -> Assertions.assertInstanceOf(ArrayNode.class, levelResponse), 28 | () -> Assertions.assertEquals(LogController.LEVELS, levelResponse.findValuesAsText("level"))); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /docs/antora.yml: -------------------------------------------------------------------------------- 1 | name: quarkus-logging-manager 2 | title: Logging Manager 3 | version: dev 4 | nav: 5 | - modules/ROOT/nav.adoc 6 | -------------------------------------------------------------------------------- /docs/modules/ROOT/assets/images/.keepme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quarkiverse/quarkus-logging-manager/1db9875b8e6cc1221ba7b2b1353b6974981c4422/docs/modules/ROOT/assets/images/.keepme -------------------------------------------------------------------------------- /docs/modules/ROOT/assets/images/logmanager.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 20 | 23 | 65 | 67 | 69 | 71 | 72 | -------------------------------------------------------------------------------- /docs/modules/ROOT/assets/images/openapi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quarkiverse/quarkus-logging-manager/1db9875b8e6cc1221ba7b2b1353b6974981c4422/docs/modules/ROOT/assets/images/openapi.png -------------------------------------------------------------------------------- /docs/modules/ROOT/examples/.keepme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quarkiverse/quarkus-logging-manager/1db9875b8e6cc1221ba7b2b1353b6974981c4422/docs/modules/ROOT/examples/.keepme -------------------------------------------------------------------------------- /docs/modules/ROOT/nav.adoc: -------------------------------------------------------------------------------- 1 | * xref:index.adoc[Logging Manager] 2 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/includes/attributes.adoc: -------------------------------------------------------------------------------- 1 | :project-version: 3.3.4 2 | 3 | :examples-dir: ./../examples/ -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/includes/quarkus-logging-manager.adoc: -------------------------------------------------------------------------------- 1 | 2 | :summaryTableId: quarkus-logging-manager 3 | [.configuration-legend] 4 | icon:lock[title=Fixed at build time] Configuration property fixed at build time - All other configuration properties are overridable at runtime 5 | [.configuration-reference.searchable, cols="80,.^10,.^10"] 6 | |=== 7 | 8 | h|[[quarkus-logging-manager_configuration]]link:#quarkus-logging-manager_configuration[Configuration property] 9 | 10 | h|Type 11 | h|Default 12 | 13 | a|icon:lock[title=Fixed at build time] [[quarkus-logging-manager_quarkus-logging-manager-base-path]]`link:#quarkus-logging-manager_quarkus-logging-manager-base-path[quarkus.logging-manager.base-path]` 14 | 15 | 16 | [.description] 17 | -- 18 | The base path 19 | 20 | ifdef::add-copy-button-to-env-var[] 21 | Environment variable: env_var_with_copy_button:+++QUARKUS_LOGGING_MANAGER_BASE_PATH+++[] 22 | endif::add-copy-button-to-env-var[] 23 | ifndef::add-copy-button-to-env-var[] 24 | Environment variable: `+++QUARKUS_LOGGING_MANAGER_BASE_PATH+++` 25 | endif::add-copy-button-to-env-var[] 26 | --|string 27 | |`logging-manager` 28 | 29 | 30 | a|icon:lock[title=Fixed at build time] [[quarkus-logging-manager_quarkus-logging-manager-openapi-included]]`link:#quarkus-logging-manager_quarkus-logging-manager-openapi-included[quarkus.logging-manager.openapi.included]` 31 | 32 | 33 | [.description] 34 | -- 35 | Whether to include the Logger Manager endpoints in the generated OpenAPI document 36 | 37 | ifdef::add-copy-button-to-env-var[] 38 | Environment variable: env_var_with_copy_button:+++QUARKUS_LOGGING_MANAGER_OPENAPI_INCLUDED+++[] 39 | endif::add-copy-button-to-env-var[] 40 | ifndef::add-copy-button-to-env-var[] 41 | Environment variable: `+++QUARKUS_LOGGING_MANAGER_OPENAPI_INCLUDED+++` 42 | endif::add-copy-button-to-env-var[] 43 | --|boolean 44 | |`false` 45 | 46 | 47 | a|icon:lock[title=Fixed at build time] [[quarkus-logging-manager_quarkus-logging-manager-openapi-tag]]`link:#quarkus-logging-manager_quarkus-logging-manager-openapi-tag[quarkus.logging-manager.openapi-tag]` 48 | 49 | 50 | [.description] 51 | -- 52 | The tag to use if OpenAPI is included 53 | 54 | ifdef::add-copy-button-to-env-var[] 55 | Environment variable: env_var_with_copy_button:+++QUARKUS_LOGGING_MANAGER_OPENAPI_TAG+++[] 56 | endif::add-copy-button-to-env-var[] 57 | ifndef::add-copy-button-to-env-var[] 58 | Environment variable: `+++QUARKUS_LOGGING_MANAGER_OPENAPI_TAG+++` 59 | endif::add-copy-button-to-env-var[] 60 | --|string 61 | |`Logging-manager` 62 | 63 | 64 | a|icon:lock[title=Fixed at build time] [[quarkus-logging-manager_quarkus-logging-manager-always-include]]`link:#quarkus-logging-manager_quarkus-logging-manager-always-include[quarkus.logging-manager.always-include]` 65 | 66 | 67 | [.description] 68 | -- 69 | Always include this. By default, this will always be included. Setting this to false will also exclude this in Prod 70 | 71 | ifdef::add-copy-button-to-env-var[] 72 | Environment variable: env_var_with_copy_button:+++QUARKUS_LOGGING_MANAGER_ALWAYS_INCLUDE+++[] 73 | endif::add-copy-button-to-env-var[] 74 | ifndef::add-copy-button-to-env-var[] 75 | Environment variable: `+++QUARKUS_LOGGING_MANAGER_ALWAYS_INCLUDE+++` 76 | endif::add-copy-button-to-env-var[] 77 | --|boolean 78 | |`true` 79 | 80 | 81 | a| [[quarkus-logging-manager_quarkus-logging-manager-enable]]`link:#quarkus-logging-manager_quarkus-logging-manager-enable[quarkus.logging-manager.enable]` 82 | 83 | 84 | [.description] 85 | -- 86 | If Logging Manager should be enabled. By default, Logging Manager is enabled if it is included (see `always-include`). 87 | 88 | ifdef::add-copy-button-to-env-var[] 89 | Environment variable: env_var_with_copy_button:+++QUARKUS_LOGGING_MANAGER_ENABLE+++[] 90 | endif::add-copy-button-to-env-var[] 91 | ifndef::add-copy-button-to-env-var[] 92 | Environment variable: `+++QUARKUS_LOGGING_MANAGER_ENABLE+++` 93 | endif::add-copy-button-to-env-var[] 94 | --|boolean 95 | |`true` 96 | 97 | |=== -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/index.adoc: -------------------------------------------------------------------------------- 1 | = Quarkus Logging Manager 2 | 3 | include::./includes/attributes.adoc[] 4 | 5 | The Quarkus Logging Manager Extension provides you endpoints to visualize and manage the log level of your loggers. 6 | 7 | == Installation 8 | 9 | If you want to use this extension, you need to add the `io.quarkiverse.loggingmanager:quarkus-logging-manager` extension first to your build file. 10 | 11 | For instance, with Maven, add the following dependency to your POM file: 12 | 13 | [source,xml,subs=attributes+] 14 | ---- 15 | 16 | io.quarkiverse.loggingmanager 17 | quarkus-logging-manager 18 | ${logger-manager.version} 19 | runtime 20 | 21 | 22 | ---- 23 | 24 | == OpenAPI 25 | 26 | You can include the Logger Manager API in the OpenAPI document (and thus also Swagger UI). This needs to be enabled via config: 27 | 28 | [source,properties] 29 | ---- 30 | quarkus.logging-manager.openapi.included=true 31 | ---- 32 | 33 | Simply run your application with `mvn quarkus:dev` and execute your code. This will then add the following to your OpenAPI: 34 | 35 | image::openapi.png[Logging Manager OpenAPI] 36 | 37 | == Security 38 | 39 | Security of endpoints is important and we do not want to allow unknown people to know (or worse, change!) the log levels of our applications. 40 | Fortunately we can secure our endpoints using Quarkus' default security mechanism, as described in Security Overview. 41 | All you have to do is define your application.properties similar to this: 42 | 43 | [source,properties] 44 | ---- 45 | quarkus.http.auth.basic=true # If you want basic auth. Multiple auth mechanism are supported 46 | 47 | quarkus.http.auth.policy.admin-access.roles-allowed=admin 48 | quarkus.http.auth.permission.roles1.paths=/q/logging-manager 49 | quarkus.http.auth.permission.roles1.policy=admin-access 50 | ---- 51 | 52 | And, in case you chose Basic Auth, provide a IdentityProvider (either by implementing one or adding an extension that provides one). 53 | Quarkus will take care of matching the paths (in this case /q/logging-manager to the policy you defined and granting or denying access). 54 | Then you can also secure all the endpoints in your application using this configuration. 55 | 56 | 57 | [[extension-configuration-reference]] 58 | == Extension Configuration Reference 59 | 60 | include::includes/quarkus-logging-manager.adoc[leveloffset=+1, opts=optional] 61 | -------------------------------------------------------------------------------- /docs/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | io.quarkiverse.loggingmanager 6 | quarkus-logging-manager-parent 7 | 999-SNAPSHOT 8 | ../pom.xml 9 | 10 | 11 | quarkus-logging-manager-docs 12 | Quarkus - Logging Manager - Documentation 13 | 14 | 15 | 16 | 17 | io.quarkiverse.loggingmanager 18 | quarkus-logging-manager-deployment 19 | ${project.version} 20 | 21 | 22 | 23 | 24 | modules/ROOT/examples 25 | 26 | 27 | io.quarkus 28 | quarkus-maven-plugin 29 | 30 | 31 | 32 | build 33 | 34 | 35 | 36 | 37 | 38 | it.ozimov 39 | yaml-properties-maven-plugin 40 | 41 | 42 | initialize 43 | 44 | read-project-properties 45 | 46 | 47 | 48 | ${project.basedir}/../.github/project.yml 49 | 50 | 51 | 52 | 53 | 54 | 55 | maven-resources-plugin 56 | 57 | 58 | copy-resources 59 | generate-resources 60 | 61 | copy-resources 62 | 63 | 64 | ${project.basedir}/modules/ROOT/pages/includes/ 65 | 66 | 67 | ${project.basedir}/../target/asciidoc/generated/config/ 68 | quarkus-logging-manager.adoc 69 | false 70 | 71 | 72 | ${project.basedir}/templates/includes 73 | attributes.adoc 74 | true 75 | 76 | 77 | 78 | 79 | 80 | copy-images 81 | prepare-package 82 | 83 | copy-resources 84 | 85 | 86 | ${project.build.directory}/generated-docs/_images/ 87 | 88 | 89 | ${project.basedir}/modules/ROOT/assets/images/ 90 | false 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | org.asciidoctor 99 | asciidoctor-maven-plugin 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /docs/templates/includes/attributes.adoc: -------------------------------------------------------------------------------- 1 | :project-version: ${release.current-version} 2 | 3 | :examples-dir: ./../examples/ -------------------------------------------------------------------------------- /openapi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quarkiverse/quarkus-logging-manager/1db9875b8e6cc1221ba7b2b1353b6974981c4422/openapi.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.quarkiverse 7 | quarkiverse-parent 8 | 20 9 | 10 | 11 | io.quarkiverse.loggingmanager 12 | quarkus-logging-manager-parent 13 | 999-SNAPSHOT 14 | pom 15 | 16 | Quarkus - Logging Manager - Parent 17 | 18 | 19 | deployment 20 | runtime 21 | 22 | 23 | 24 | scm:git:git@github.com:quarkiverse/quarkus-logging-manager.git 25 | scm:git:git@github.com:quarkiverse/quarkus-logging-manager.git 26 | https://github.com/quarkiverse/quarkus-logging-manager 27 | HEAD 28 | 29 | 30 | 3.14.0 31 | 17 32 | UTF-8 33 | UTF-8 34 | 3.20.0 35 | 36 | 37 | 38 | 39 | io.quarkus 40 | quarkus-bom 41 | ${quarkus.version} 42 | pom 43 | import 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | io.quarkus 53 | quarkus-maven-plugin 54 | ${quarkus.version} 55 | 56 | 57 | org.apache.maven.plugins 58 | maven-compiler-plugin 59 | ${compiler-plugin.version} 60 | 61 | 62 | -parameters 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | docs 72 | 73 | 74 | performRelease 75 | !true 76 | 77 | 78 | 79 | docs 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /runtime/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | io.quarkiverse.loggingmanager 6 | quarkus-logging-manager-parent 7 | 999-SNAPSHOT 8 | ../pom.xml 9 | 10 | 11 | quarkus-logging-manager 12 | Quarkus - Logging Manager - Runtime 13 | Provides endpoints to visualize and control the log level of your loggers. 14 | 15 | 16 | 17 | io.quarkus 18 | quarkus-core 19 | 20 | 21 | io.quarkus 22 | quarkus-vertx-http 23 | 24 | 25 | 26 | 27 | 28 | 29 | io.quarkus 30 | quarkus-extension-maven-plugin 31 | ${quarkus.version} 32 | 33 | 34 | 35 | extension-descriptor 36 | 37 | compile 38 | 39 | ${project.groupId}:${project.artifactId}-deployment:${project.version} 40 | 41 | 42 | 43 | 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-compiler-plugin 48 | 49 | 50 | 51 | io.quarkus 52 | quarkus-extension-processor 53 | ${quarkus.version} 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/loggingmanager/LevelHandler.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager; 2 | 3 | import static io.vertx.core.http.HttpMethod.GET; 4 | 5 | import io.vertx.core.Handler; 6 | import io.vertx.core.http.HttpMethod; 7 | import io.vertx.core.http.HttpServerRequest; 8 | import io.vertx.core.http.HttpServerResponse; 9 | import io.vertx.ext.web.RoutingContext; 10 | 11 | public class LevelHandler implements Handler { 12 | 13 | @Override 14 | public void handle(RoutingContext routingContext) { 15 | 16 | HttpServerRequest request = routingContext.request(); 17 | HttpMethod method = request.method(); 18 | 19 | HttpServerResponse response = routingContext.response(); 20 | response.headers().add("Content-Type", "application/json"); 21 | 22 | if (GET == method) { 23 | response.end(LogController.getLevels().build()); 24 | } else { 25 | response.end(); 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/loggingmanager/LogController.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager; 2 | 3 | import static org.jboss.logmanager.Level.ALL; 4 | import static org.jboss.logmanager.Level.CONFIG; 5 | import static org.jboss.logmanager.Level.DEBUG; 6 | import static org.jboss.logmanager.Level.ERROR; 7 | import static org.jboss.logmanager.Level.FATAL; 8 | import static org.jboss.logmanager.Level.FINE; 9 | import static org.jboss.logmanager.Level.FINER; 10 | import static org.jboss.logmanager.Level.FINEST; 11 | import static org.jboss.logmanager.Level.INFO; 12 | import static org.jboss.logmanager.Level.OFF; 13 | import static org.jboss.logmanager.Level.SEVERE; 14 | import static org.jboss.logmanager.Level.TRACE; 15 | import static org.jboss.logmanager.Level.WARN; 16 | import static org.jboss.logmanager.Level.WARNING; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Enumeration; 20 | import java.util.List; 21 | import java.util.TreeMap; 22 | import java.util.logging.Level; 23 | 24 | import org.jboss.logmanager.LogContext; 25 | import org.jboss.logmanager.Logger; 26 | 27 | import io.quarkus.vertx.http.runtime.devmode.Json; 28 | 29 | /** 30 | * Allow controlling to the log levels 31 | */ 32 | public class LogController { 33 | private static final org.jboss.logging.Logger LOG = org.jboss.logging.Logger.getLogger(LogController.class); 34 | 35 | private LogController() { 36 | } 37 | 38 | public static Json.JsonArrayBuilder getLevels() { 39 | Json.JsonArrayBuilder array = Json.array(); 40 | for (String level : LEVELS) { 41 | array.add(level); 42 | } 43 | return array; 44 | } 45 | 46 | public static Json.JsonArrayBuilder getLoggers() { 47 | LogContext logContext = LogContext.getLogContext(); 48 | TreeMap loggerMap = new TreeMap<>(); 49 | 50 | Enumeration loggerNames = logContext.getLoggerNames(); 51 | while (loggerNames.hasMoreElements()) { 52 | String loggerName = loggerNames.nextElement(); 53 | Json.JsonObjectBuilder jsonObject = getLogger(loggerName); 54 | if (jsonObject != null) { 55 | loggerMap.put(loggerName, jsonObject); 56 | } 57 | } 58 | 59 | List orderedLoggers = new ArrayList<>(loggerMap.values()); 60 | Json.JsonArrayBuilder jsonArray = Json.array(); 61 | jsonArray.addAll(orderedLoggers); 62 | return jsonArray; 63 | } 64 | 65 | public static Json.JsonObjectBuilder getLogger(String loggerName) { 66 | LogContext logContext = LogContext.getLogContext(); 67 | if (loggerName != null && !loggerName.isEmpty()) { 68 | Logger logger = logContext.getLogger(loggerName); 69 | Json.JsonObjectBuilder jsonObject = Json.object(); 70 | jsonObject.put("name", loggerName); 71 | jsonObject.put("effectiveLevel", getEffectiveLogLevel(logger)); 72 | jsonObject.put("configuredLevel", getConfiguredLogLevel(logger)); 73 | return jsonObject; 74 | } 75 | return null; 76 | } 77 | 78 | public static void updateLogLevel(String loggerName, String levelValue) { 79 | LogContext logContext = LogContext.getLogContext(); 80 | Logger logger = logContext.getLogger(loggerName); 81 | java.util.logging.Level level; 82 | if (levelValue == null || levelValue.isBlank()) { 83 | if (logger.getParent() != null) { 84 | level = logger.getParent().getLevel(); 85 | } else { 86 | throw new IllegalArgumentException("The level of the root logger cannot be set to null"); 87 | } 88 | } else { 89 | level = Level.parse(levelValue); 90 | } 91 | logger.setLevel(level); 92 | LOG.info("Log level updated [" + loggerName + "] changed to [" + levelValue + "]"); 93 | } 94 | 95 | public static String getConfiguredLogLevel(Logger logger) { 96 | java.util.logging.Level level = logger.getLevel(); 97 | return level != null ? level.getName() : null; 98 | } 99 | 100 | public static String getEffectiveLogLevel(Logger logger) { 101 | if (logger == null) { 102 | return null; 103 | } 104 | if (logger.getLevel() != null) { 105 | return logger.getLevel().getName(); 106 | } 107 | return getEffectiveLogLevel(logger.getParent()); 108 | } 109 | 110 | public static final List LEVELS = List.of( 111 | OFF.getName(), 112 | SEVERE.getName(), 113 | ERROR.getName(), 114 | FATAL.getName(), 115 | WARNING.getName(), 116 | WARN.getName(), 117 | INFO.getName(), 118 | DEBUG.getName(), 119 | TRACE.getName(), 120 | CONFIG.getName(), 121 | FINE.getName(), 122 | FINER.getName(), 123 | FINEST.getName(), 124 | ALL.getName()); 125 | } 126 | -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/loggingmanager/LoggerHandler.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager; 2 | 3 | import static io.vertx.core.http.HttpMethod.GET; 4 | import static io.vertx.core.http.HttpMethod.POST; 5 | 6 | import java.util.Objects; 7 | 8 | import io.vertx.core.Handler; 9 | import io.vertx.core.http.HttpMethod; 10 | import io.vertx.core.http.HttpServerRequest; 11 | import io.vertx.core.http.HttpServerResponse; 12 | import io.vertx.ext.web.RoutingContext; 13 | 14 | /** 15 | * Handler for logger-related HTTP endpoints. 16 | * Supports GET requests to retrieve logger information and POST requests to update logger levels. 17 | */ 18 | public class LoggerHandler implements Handler { 19 | private static final String LOGGER_NAME_PARAM = "loggerName"; 20 | private static final String LOGGER_LEVEL_PARAM = "loggerLevel"; 21 | 22 | /** 23 | * Handles incoming HTTP requests by delegating to appropriate method handlers. 24 | * 25 | * @param routingContext The Vert.x routing context 26 | */ 27 | @Override 28 | public void handle(RoutingContext routingContext) { 29 | HttpServerRequest request = routingContext.request(); 30 | HttpServerResponse response = routingContext.response(); 31 | HttpMethod method = request.method(); 32 | 33 | if (GET == method) { 34 | handleGet(request, response); 35 | } else if (POST == method) { 36 | handlePost(request, response); 37 | } else { 38 | response.setStatusCode(405).end(); // Method not allowed 39 | } 40 | } 41 | 42 | /** 43 | * Handles GET requests to retrieve logger information. 44 | * Returns all loggers if no logger name is specified, or details for a specific logger. 45 | * 46 | * @param request The HTTP request 47 | * @param response The HTTP response 48 | */ 49 | private void handleGet(HttpServerRequest request, HttpServerResponse response) { 50 | response.headers().add("Content-Type", "application/json"); 51 | 52 | String loggerName = request.getParam(LOGGER_NAME_PARAM); 53 | if (loggerName == null || loggerName.isEmpty()) { 54 | response.end(LogController.getLoggers().build()); 55 | } else { 56 | response.end(Objects.requireNonNull(LogController.getLogger(loggerName)).build()); 57 | } 58 | } 59 | 60 | /** 61 | * Handles POST requests to update logger levels. 62 | * Updates the specified logger with the provided level or removes the level if none specified. 63 | * 64 | * @param request The HTTP request 65 | * @param response The HTTP response 66 | */ 67 | private void handlePost(HttpServerRequest request, HttpServerResponse response) { 68 | String contentType = request.getHeader("Content-Type"); 69 | if (!"application/x-www-form-urlencoded".equals(contentType)) { 70 | response.setStatusCode(415).end(); 71 | return; 72 | } 73 | 74 | String loggerName = request.getFormAttribute(LOGGER_NAME_PARAM); 75 | String loggerLevel = request.getFormAttribute(LOGGER_LEVEL_PARAM); 76 | 77 | if (loggerLevel == null || loggerLevel.isEmpty()) { 78 | LogController.updateLogLevel(loggerName, null); 79 | } else { 80 | LogController.updateLogLevel(loggerName, loggerLevel); 81 | } 82 | 83 | response.setStatusCode(201).end(); 84 | } 85 | } -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/loggingmanager/LoggerManagerRecorder.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import io.quarkus.runtime.annotations.Recorder; 6 | import io.vertx.core.Handler; 7 | import io.vertx.ext.web.Route; 8 | import io.vertx.ext.web.RoutingContext; 9 | 10 | @Recorder 11 | public class LoggerManagerRecorder { 12 | 13 | public Handler loggerHandler() { 14 | return new LoggerHandler(); 15 | } 16 | 17 | public Handler levelHandler() { 18 | return new LevelHandler(); 19 | } 20 | 21 | public Consumer routeConsumer(Handler bodyHandler, LoggingManagerRuntimeConfig runtimeConfig) { 22 | if (runtimeConfig.enable()) { 23 | return route -> route.handler(bodyHandler); 24 | } else { 25 | return route -> route.handler(new LoggingManagerNotFoundHandler()); 26 | } 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/loggingmanager/LoggingManagerNotFoundHandler.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager; 2 | 3 | import io.vertx.core.Handler; 4 | import io.vertx.ext.web.RoutingContext; 5 | 6 | /** 7 | * Handling static when disabled 8 | */ 9 | public class LoggingManagerNotFoundHandler implements Handler { 10 | 11 | @Override 12 | public void handle(RoutingContext event) { 13 | event.response().setStatusCode(404); 14 | event.response().end(); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/loggingmanager/LoggingManagerRuntimeConfig.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager; 2 | 3 | import io.quarkus.runtime.annotations.ConfigPhase; 4 | import io.quarkus.runtime.annotations.ConfigRoot; 5 | import io.smallrye.config.ConfigMapping; 6 | import io.smallrye.config.WithDefault; 7 | 8 | @ConfigMapping(prefix = "quarkus.logging-manager") 9 | @ConfigRoot(phase = ConfigPhase.RUN_TIME) 10 | public interface LoggingManagerRuntimeConfig { 11 | 12 | /** 13 | * If Logging Manager should be enabled. By default, Logging Manager is enabled if it is included (see 14 | * {@code always-include}). 15 | */ 16 | @WithDefault("true") 17 | boolean enable(); 18 | } 19 | -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/loggingmanager/devui/LoggingManagerJsonRpcService.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.loggingmanager.devui; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Enumeration; 5 | import java.util.List; 6 | 7 | import org.jboss.logmanager.LogContext; 8 | import org.jboss.logmanager.Logger; 9 | 10 | import io.quarkiverse.loggingmanager.LogController; 11 | import io.smallrye.common.annotation.NonBlocking; 12 | 13 | public class LoggingManagerJsonRpcService { 14 | @NonBlocking 15 | public List getLoggers() { 16 | List infoList = new ArrayList<>(); 17 | LogContext logContext = LogContext.getLogContext(); 18 | Enumeration loggerNames = logContext.getLoggerNames(); 19 | while (loggerNames.hasMoreElements()) { 20 | infoList.add(getLoggerInfo(logContext, loggerNames.nextElement())); 21 | } 22 | return infoList; 23 | } 24 | 25 | private static LoggerInfo getLoggerInfo(LogContext logContext, String loggerName) { 26 | Logger logger = logContext.getLogger(loggerName); 27 | String effectiveLevel = LogController.getEffectiveLogLevel(logger); 28 | String configuredLevel = LogController.getConfiguredLogLevel(logger); 29 | return new LoggerInfo(loggerName, effectiveLevel, configuredLevel); 30 | } 31 | 32 | @NonBlocking 33 | public void updateLogger(String loggerName, String logLevel) { 34 | LogController.updateLogLevel(loggerName, logLevel); 35 | } 36 | 37 | public static class LoggerInfo { 38 | private final String name; 39 | private final String effectiveLevel; 40 | private final String configuredLevel; 41 | 42 | LoggerInfo(String name, String effectiveLevel, String configuredLevel) { 43 | this.name = name; 44 | this.effectiveLevel = effectiveLevel; 45 | this.configuredLevel = configuredLevel; 46 | } 47 | 48 | public String getName() { 49 | return this.name; 50 | } 51 | 52 | public String getEffectiveLevel() { 53 | return this.effectiveLevel; 54 | } 55 | 56 | public String getConfiguredLevel() { 57 | return configuredLevel; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /runtime/src/main/resources/META-INF/quarkus-extension.yaml: -------------------------------------------------------------------------------- 1 | name: "Logging Manager" 2 | artifact: ${project.groupId}:${project.artifactId}:${project.version} 3 | metadata: 4 | short-name: "logging manager" 5 | keywords: 6 | - "logging" 7 | - "logging manager" 8 | - "log" 9 | - "logging levels" 10 | - "log level" 11 | - "log file" 12 | categories: 13 | - "logging" 14 | config: 15 | - "quarkus.logging-manager." 16 | status: "stable" 17 | guide: "https://quarkiverse.github.io/quarkiverse-docs/quarkus-logging-manager/dev/index.html" 18 | icon-url: "https://raw.githubusercontent.com/quarkiverse/quarkus-logging-manager/main/docs/modules/ROOT/assets/images/logmanager.svg" 19 | --------------------------------------------------------------------------------