├── .editorconfig ├── .github └── workflows │ ├── check.yml │ └── releaseExtension.yml ├── .gitignore ├── .idea ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml └── inspectionProfiles │ └── Project_Default.xml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── HEADER ├── LICENSE ├── NOTICE ├── README.adoc ├── build.gradle.kts ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── renovate.json5 ├── settings.gradle.kts └── src ├── hivemq-extension └── conf │ └── examples │ └── config.xml ├── integrationTest ├── java │ └── com │ │ └── hivemq │ │ └── extensions │ │ └── log │ │ ├── FullConfigIT.java │ │ ├── FullConfigNoPayloadIT.java │ │ ├── FullConfigNoPayloadNoVerboseIT.java │ │ ├── FullConfigNoVerboseIT.java │ │ ├── FullConfigXmlIT.java │ │ ├── FullConfigXmlNoPayloadIT.java │ │ ├── FullConfigXmlNoPayloadNoVerboseIT.java │ │ └── FullConfigXmlNoVerboseIT.java └── resources │ ├── fullConfig.properties │ ├── fullConfig.xml │ ├── fullConfigNoPayload.properties │ ├── fullConfigNoPayload.xml │ ├── fullConfigNoPayloadNoVerbose.properties │ ├── fullConfigNoPayloadNoVerbose.xml │ ├── fullConfigNoVerbose.properties │ ├── fullConfigNoVerbose.xml │ └── logback-test.xml ├── main ├── java │ └── com │ │ └── hivemq │ │ └── extensions │ │ └── log │ │ └── mqtt │ │ └── message │ │ ├── ExtensionConstants.java │ │ ├── MqttMessageLogExtensionMain.java │ │ ├── config │ │ ├── ExtensionConfig.java │ │ ├── ExtensionConfigProperties.java │ │ ├── ExtensionConfigReader.java │ │ ├── ExtensionConfigXml.java │ │ └── XmlParser.java │ │ ├── initializer │ │ ├── ClientInitializerImpl.java │ │ └── ClientInitializerImpl4_2.java │ │ ├── interceptor │ │ ├── ConnackOutboundInterceptorImpl.java │ │ ├── ConnectDisconnectEventListener.java │ │ ├── ConnectInboundInterceptorImpl.java │ │ ├── DisconnectInboundInterceptorImpl.java │ │ ├── DisconnectOutboundInterceptorImpl.java │ │ ├── PingreqInboundInterceptorImpl.java │ │ ├── PingrespOutboundInterceptorImpl.java │ │ ├── PubackInboundInterceptorImpl.java │ │ ├── PubackOutboundInterceptorImpl.java │ │ ├── PubcompInboundInterceptorImpl.java │ │ ├── PubcompOutboundInterceptorImpl.java │ │ ├── PublishInboundInterceptorImpl.java │ │ ├── PublishOutboundInterceptorImpl.java │ │ ├── PubrecInboundInterceptorImpl.java │ │ ├── PubrecOutboundInterceptorImpl.java │ │ ├── PubrelInboundInterceptorImpl.java │ │ ├── PubrelOutboundInterceptorImpl.java │ │ ├── SubackOutboundInterceptorImpl.java │ │ ├── SubscribeInboundInterceptorImpl.java │ │ ├── UnsubackOutboundInterceptorImpl.java │ │ └── UnsubscribeInboundInterceptorImpl.java │ │ └── util │ │ └── MessageLogUtil.java └── resources │ └── config.xsd └── test ├── java └── com │ └── hivemq │ └── extensions │ └── log │ └── mqtt │ └── message │ ├── MqttMessageLogExtensionMainTest.java │ ├── config │ ├── ExtensionConfigPropertiesTest.java │ └── ExtensionConfigReaderTest.java │ └── util │ ├── LogbackTestAppender.java │ ├── MessageLogUtilTest.java │ └── PacketUtil.java └── resources ├── test-conf └── mqttMessageLog.properties ├── test-invalid-xml-conf └── conf │ └── config.xml └── test-xml-conf └── conf └── config.xml /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: CI Check 2 | 3 | on: 4 | push: 5 | branches: [ "**" ] 6 | 7 | jobs: 8 | check: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 13 | - name: Setup Java 14 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4 15 | with: 16 | distribution: temurin 17 | java-version: 11 18 | - name: Setup Gradle 19 | uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4 20 | - name: Check 21 | run: ./gradlew check 22 | env: 23 | ORG_GRADLE_PROJECT_dockerHubUsername: ${{ secrets.DOCKER_USERNAME }} 24 | ORG_GRADLE_PROJECT_dockerHubPassword: ${{ secrets.DOCKER_TOKEN }} 25 | -------------------------------------------------------------------------------- /.github/workflows/releaseExtension.yml: -------------------------------------------------------------------------------- 1 | name: Release Extension 2 | 3 | on: 4 | release: 5 | types: [ published ] 6 | 7 | jobs: 8 | release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 13 | - name: Setup Java 14 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4 15 | with: 16 | distribution: temurin 17 | java-version: 11 18 | - name: Setup Gradle 19 | uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4 20 | - name: Build Zip 21 | run: ./gradlew hivemqExtensionZip 22 | - name: Upload GitHub Release Asset 23 | run: gh release upload ${{ github.event.release.tag_name }} ./build/hivemq-extension/hivemq-mqtt-message-log-extension-${{ github.event.release.name }}.zip 24 | env: 25 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle 2 | .gradle 3 | build/ 4 | 5 | # IntelliJ 6 | out/ 7 | *.iml 8 | .idea/* 9 | !.idea/codeStyles 10 | !.idea/inspectionProfiles 11 | !.idea/runConfigurations 12 | 13 | .java-version 14 | .DS_Store 15 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # HiveMQ Code of Conduct 2 | 3 | Please refer to our [HiveMQ Code of Conduct](https://github.com/hivemq/hivemq-community/blob/master/code-of-conduct.md). 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Welcome to the HiveMQ Community! 4 | Glad to see your interest in contributing to HiveMQ Mqtt Message Log Extension. 5 | Please checkout our [Contribution Guide](https://github.com/hivemq/hivemq-community/blob/master/CONTRIBUTING.adoc) to make sure your contribution will be accepted by the HiveMQ team. 6 | 7 | For information on how the HiveMQ Community is organized and how contributions will be accepted please have a look at our [HiveMQ Community Repo](https://github.com/hivemq/hivemq-community). 8 | -------------------------------------------------------------------------------- /HEADER: -------------------------------------------------------------------------------- 1 | Copyright 2019-present HiveMQ GmbH 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2018-present HiveMQ GmbH 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use the contents of this repository except in 5 | compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | :hivemq-blog-tools: http://www.hivemq.com/mqtt-toolbox 2 | :hivemq-support: http://www.hivemq.com/support/ 3 | :hivemq-extension-download: https://www.hivemq.com/extension/mqtt-message-log-extension/ 4 | 5 | = HiveMQ MQTT Message Log Extension 6 | 7 | image:https://img.shields.io/badge/Extension_Type-Logging-orange?style=for-the-badge[Extension Type] 8 | image:https://img.shields.io/github/v/release/hivemq/hivemq-mqtt-message-log-extension?style=for-the-badge[GitHub release (latest by date),link=https://github.com/hivemq/hivemq-mqtt-message-log-extension/releases/latest] 9 | image:https://img.shields.io/github/license/hivemq/hivemq-mqtt-message-log-extension?style=for-the-badge&color=brightgreen[GitHub,link=LICENSE] 10 | image:https://img.shields.io/github/actions/workflow/status/hivemq/hivemq-mqtt-message-log-extension/check.yml?branch=master&style=for-the-badge[GitHub Workflow Status,link=https://github.com/hivemq/hivemq-mqtt-message-log-extension/actions/workflows/check.yml?query=branch%3Amaster] 11 | 12 | == Prerequisites 13 | 14 | * HiveMQ Enterprise Edition (EE) 4.2.0 or later 15 | * HiveMQ Community Edition (CE) 2020.1 or later 16 | 17 | == Purpose 18 | 19 | The HiveMQ MQTT Message Log Extension provides custom logging events on clients communicating with the broker. 20 | This is useful for debugging and development purposes. 21 | 22 | *The extension logs the following events:* 23 | 24 | [cols="6,2,2"] 25 | |=== 26 | |Event | Config Property | Minimum Version 27 | 28 | |A client connects to HiveMQ | client-connect | 4.2 EE or 2020.1 CE 29 | |A client disconnects from HiveMQ | client-disconnect | 4.2 EE or 2020.1 CE 30 | |A client sends a PUBLISH message | publish-received | 4.2 EE or 2020.1 CE 31 | |A client sends a SUBSCRIBE message | subscribe-received |4.2 EE or 2020.1 CE 32 | |HiveMQ sends a PUBLISH message to a client | publish-send |4.2 EE or 2020.1 CE 33 | |A client sends an UNSUBSCRIBE message | unsubscribe-received | 4.3 EE or 2020.1 CE 34 | |A client send a PING request | ping-request-received | 4.3 EE or 2020.1 CE 35 | |A client completes a received QoS 1 PUBLISH with a PUBACK message | puback-received | 4.3 EE or 2020.1 CE 36 | |A client acknowledges the reception of a QoS 2 PUBLISH with a PUBREC message | pubrec-received | 4.3 EE or 2020.1 CE 37 | |A client completes a sent QoS 2 PUBLISH with a PUBREL message | pubrel-received | 4.3 EE or 2020.1 CE 38 | |A client completes a received QoS 2 PUBLISH with a PUBCOMP message | pubcomp-received | 4.3 EE or 2020.1 CE 39 | |HiveMQ sends a CONNACK message to a client | connack-send | 4.3 EE or 2020.1 CE 40 | |HiveMQ disconnects a client with a DISCONNECT message | client-disconnect | 4.3 EE or 2020.1 CE 41 | |HiveMQ sends a SUBACK message to a client | suback-send | 4.3 EE or 2020.1 CE 42 | |HiveMQ sends an UNSUBACK message to a client | unsuback-send | 4.3 EE or 2020.1 CE 43 | |HiveMQ sends a PING response to a client | ping-response-send | 4.3 EE or 2020.1 CE 44 | |HiveMQ completes a received QoS 1 PUBLISH with a PUBACK message | puback-send | 4.3 EE or 2020.1 CE 45 | |HiveMQ acknowledges the reception of a QoS 2 PUBLISH with a PUBREC message | pubrec-send | 4.3 EE or 2020.1 CE 46 | |HiveMQ completes a sent QoS 2 PUBLISH with a PUBREL message | pubrel-send | 4.3 EE or 2020.1 CE 47 | |HiveMQ completes a received QoS 2 PUBLISH with a PUBCOMP message | pubcomp-send | 4.3 EE or 2020.1 CE 48 | |=== 49 | 50 | == Installation 51 | 52 | * Download the extension from the {hivemq-extension-download}[HiveMQ Marketplace^]. 53 | * Copy the content of the zip file to the `extensions` folder of your HiveMQ nodes. 54 | * Configure the extension by adding a `config.xml` file in the extension's `conf` folder. 55 | ** For your convenience, we provide an example configuration `conf/examples/config.xml` that you can copy and modify as desired. 56 | ** The file must be located in `HIVEMQ_HOME/extensions/hivemq-mqtt-message-log-extension/conf/config.xml`. 57 | 58 | NOTE: Starting with release 1.2.0 of the extension, the legacy configuration file `mqttMessageLog.properties` is deprecated. 59 | Support for the legacy configuration will be removed in a future release. 60 | 61 | == Configuration 62 | 63 | === Event Configuration 64 | 65 | By default, all MQTT events are logged. 66 | It is possible to opt out of specific log event types by adding a `config.xml` file to your `hivemq-mqtt-message-log-extension/conf` folder. 67 | An example configuration file is available in `conf/examples/`, which removes the logging of PUBLISH messages. 68 | 69 | === General Configuration 70 | 71 | |=== 72 | |Config Property | Description | Default 73 | 74 | |verbose |Log detailed information about an MQTT event | false 75 | |payload |Log the payload of a message | true 76 | |=== 77 | 78 | Normally, events only log important information. 79 | Set the `verbose` property to `true` to log all available information. 80 | You can see the difference between normal logging and verbose logging in the <> section. 81 | 82 | CAUTION: use `verbose=true` very carefully as it will flood your log immediately. 83 | 84 | Set the `payload` property to `false` if you want to suppress logging payloads (i.e. for publish-received, publish-send, and will messages). 85 | 86 | == First Steps 87 | 88 | Connect with an {hivemq-blog-tools}[MQTT client] of your choice. 89 | You should see a log message with its client identifier, MQTT version, clean start flag and session expiry interval. 90 | 91 | [[example]] 92 | == Examples 93 | 94 | === Verbose CONNECT message with payload 95 | 96 | [source,bash] 97 | ---- 98 | "17:26:23.602 INFO - Received CONNECT from client 'clientid': Protocol version: 'V_5', Clean Start: 'false', 99 | Session Expiry Interval: '10000', Keep Alive: '20000', Maximum Packet Size: '40000', 100 | Receive Maximum: '30000', Topic Alias Maximum: '50000', Request Problem Information: 'true', 101 | Request Response Information: 'false', Username: 'the username', Password: 'the password', 102 | Auth Method: 'auth method', Auth Data (Base64): 'YXV0aCBkYXRh', 103 | User Properties: [Name: 'name0', Value: 'value0'], [Name: 'name1', Value: 'value1'], 104 | Will: { Topic: 'willtopic', Payload: 'payload', QoS: '1', Retained: 'false', Message Expiry Interval: '1234', 105 | Duplicate Delivery: 'false', Correlation Data: 'data', Response Topic: 'response topic', 106 | Content Type: 'content type', Payload Format Indicator: 'UTF_8', Subscription Identifiers: '[1, 2, 3, 4]', 107 | User Properties: [Name: 'name0', Value: 'value0'], [Name: 'name1', Value: 'value1'], 108 | [Name: 'name2', Value: 'value2'], Will Delay: '100' }" 109 | ---- 110 | 111 | === Basic CONNECT message 112 | 113 | [source,bash] 114 | ---- 115 | "17:26:23.602 INFO - Received CONNECT from client 'clientid': Protocol version: 'V_5', Clean Start: 'false', Session Expiry Interval: '10000'" 116 | ---- 117 | 118 | == Need Help? 119 | 120 | If you encounter any problems, we are happy to help. 121 | The best place to get in contact is our {hivemq-support}[support^]. 122 | 123 | == Contributing 124 | 125 | If you want to contribute to HiveMQ MQTT Message Log Extension, see the link:CONTRIBUTING.md[contribution guidelines]. 126 | 127 | == License 128 | 129 | HiveMQ MQTT Message Log Extension is licensed under the `APACHE LICENSE, VERSION 2.0`. 130 | A copy of the license can be found link:LICENSE[here]. 131 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.hivemq.extension) 3 | alias(libs.plugins.defaults) 4 | alias(libs.plugins.oci) 5 | alias(libs.plugins.license) 6 | } 7 | 8 | group = "com.hivemq.extensions" 9 | description = "HiveMQ Mqtt Message Log Extension" 10 | 11 | hivemqExtension { 12 | name = "HiveMQ Mqtt Message Log Extension" 13 | author = "HiveMQ" 14 | priority = 1000 15 | startPriority = 1000 16 | sdkVersion = libs.versions.hivemq.extensionSdk 17 | 18 | resources { 19 | from("LICENSE") 20 | from("src/main/resources/config.xsd") { into("conf") } 21 | } 22 | } 23 | 24 | java { 25 | toolchain { 26 | languageVersion = JavaLanguageVersion.of(11) 27 | } 28 | } 29 | 30 | dependencies { 31 | compileOnly(libs.jetbrains.annotations) 32 | implementation(libs.commonsLang) 33 | implementation(libs.jaxb.api) 34 | runtimeOnly(libs.jaxb.impl) 35 | } 36 | 37 | oci { 38 | registries { 39 | dockerHub { 40 | optionalCredentials() 41 | } 42 | } 43 | imageMapping { 44 | mapModule("com.hivemq", "hivemq-enterprise") { 45 | toImage("hivemq/hivemq4") 46 | } 47 | } 48 | imageDefinitions.register("main") { 49 | allPlatforms { 50 | dependencies { 51 | runtime("com.hivemq:hivemq-enterprise:latest") { isChanging = true } 52 | } 53 | layer("main") { 54 | contents { 55 | permissions("opt/hivemq/", 0b111_111_101) 56 | permissions("opt/hivemq/extensions/", 0b111_111_101) 57 | into("opt/hivemq/extensions") { 58 | from(zipTree(tasks.hivemqExtensionZip.flatMap { it.archiveFile })) 59 | } 60 | } 61 | } 62 | } 63 | } 64 | } 65 | 66 | @Suppress("UnstableApiUsage") 67 | testing { 68 | suites { 69 | withType { 70 | useJUnitJupiter(libs.versions.junit.jupiter) 71 | } 72 | "test"(JvmTestSuite::class) { 73 | dependencies { 74 | compileOnly(libs.jetbrains.annotations) 75 | implementation(libs.mockito) 76 | implementation(libs.logback.classic) 77 | } 78 | } 79 | "integrationTest"(JvmTestSuite::class) { 80 | dependencies { 81 | compileOnly(libs.jetbrains.annotations) 82 | implementation(libs.awaitility) 83 | implementation(libs.hivemq.mqttClient) 84 | implementation(libs.testcontainers.junitJupiter) 85 | implementation(libs.testcontainers.hivemq) 86 | implementation(libs.gradleOci.junitJupiter) 87 | runtimeOnly(libs.logback.classic) 88 | } 89 | oci.of(this) { 90 | imageDependencies { 91 | runtime(project).tag("latest") 92 | } 93 | } 94 | } 95 | } 96 | } 97 | 98 | license { 99 | header = rootDir.resolve("HEADER") 100 | mapping("java", "SLASHSTAR_STYLE") 101 | exclude("**/test-conf/mqttMessageLog.properties") 102 | } 103 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | version=1.2.1 2 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | awaitility = "4.3.0" 3 | commonsLang = "3.17.0" 4 | gradleOci-junitJupiter = "0.7.0" 5 | hivemq-extensionSdk = "4.3.0" 6 | hivemq-mqttClient = "1.3.6" 7 | jaxb-api = "4.0.2" 8 | jaxb-impl = "4.0.5" 9 | jetbrains-annotations = "26.0.2" 10 | junit-jupiter = "5.10.3" 11 | logback = "1.5.18" 12 | mockito = "5.18.0" 13 | okhttp = "4.12.0" 14 | testcontainers = "1.21.1" 15 | 16 | [libraries] 17 | awaitility = { module = "org.awaitility:awaitility", version.ref = "awaitility" } 18 | commonsLang = { module = "org.apache.commons:commons-lang3", version.ref = "commonsLang" } 19 | gradleOci-junitJupiter = { module = "io.github.sgtsilvio:gradle-oci-junit-jupiter", version.ref = "gradleOci-junitJupiter" } 20 | hivemq-mqttClient = { module = "com.hivemq:hivemq-mqtt-client", version.ref = "hivemq-mqttClient" } 21 | jaxb-api = { module = "jakarta.xml.bind:jakarta.xml.bind-api", version.ref = "jaxb-api" } 22 | jaxb-impl = { module = "org.glassfish.jaxb:jaxb-runtime", version.ref = "jaxb-impl" } 23 | jetbrains-annotations = { module = "org.jetbrains:annotations", version.ref = "jetbrains-annotations" } 24 | logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback" } 25 | mockito = { module = "org.mockito:mockito-core", version.ref = "mockito" } 26 | okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } 27 | testcontainers-hivemq = { module = "org.testcontainers:hivemq", version.ref = "testcontainers" } 28 | testcontainers-junitJupiter = { module = "org.testcontainers:junit-jupiter", version.ref = "testcontainers" } 29 | 30 | [plugins] 31 | defaults = { id = "io.github.sgtsilvio.gradle.defaults", version = "0.2.0" } 32 | hivemq-extension = { id = "com.hivemq.extension", version = "4.0.0" } 33 | license = { id = "com.github.hierynomus.license", version = "0.16.1" } 34 | oci = { id = "io.github.sgtsilvio.gradle.oci", version = "0.23.0" } 35 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hivemq/hivemq-mqtt-message-log-extension/ee23728b2925a06c784371e187732b0a1c9af890/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s 90 | ' "$PWD" ) || exit 91 | 92 | # Use the maximum available, or set MAX_FD != -1 to use that value. 93 | MAX_FD=maximum 94 | 95 | warn () { 96 | echo "$*" 97 | } >&2 98 | 99 | die () { 100 | echo 101 | echo "$*" 102 | echo 103 | exit 1 104 | } >&2 105 | 106 | # OS specific support (must be 'true' or 'false'). 107 | cygwin=false 108 | msys=false 109 | darwin=false 110 | nonstop=false 111 | case "$( uname )" in #( 112 | CYGWIN* ) cygwin=true ;; #( 113 | Darwin* ) darwin=true ;; #( 114 | MSYS* | MINGW* ) msys=true ;; #( 115 | NONSTOP* ) nonstop=true ;; 116 | esac 117 | 118 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 119 | 120 | 121 | # Determine the Java command to use to start the JVM. 122 | if [ -n "$JAVA_HOME" ] ; then 123 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 124 | # IBM's JDK on AIX uses strange locations for the executables 125 | JAVACMD=$JAVA_HOME/jre/sh/java 126 | else 127 | JAVACMD=$JAVA_HOME/bin/java 128 | fi 129 | if [ ! -x "$JAVACMD" ] ; then 130 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 131 | 132 | Please set the JAVA_HOME variable in your environment to match the 133 | location of your Java installation." 134 | fi 135 | else 136 | JAVACMD=java 137 | if ! command -v java >/dev/null 2>&1 138 | then 139 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 140 | 141 | Please set the JAVA_HOME variable in your environment to match the 142 | location of your Java installation." 143 | fi 144 | fi 145 | 146 | # Increase the maximum file descriptors if we can. 147 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 148 | case $MAX_FD in #( 149 | max*) 150 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 151 | # shellcheck disable=SC2039,SC3045 152 | MAX_FD=$( ulimit -H -n ) || 153 | warn "Could not query maximum file descriptor limit" 154 | esac 155 | case $MAX_FD in #( 156 | '' | soft) :;; #( 157 | *) 158 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 159 | # shellcheck disable=SC2039,SC3045 160 | ulimit -n "$MAX_FD" || 161 | warn "Could not set maximum file descriptor limit to $MAX_FD" 162 | esac 163 | fi 164 | 165 | # Collect all arguments for the java command, stacking in reverse order: 166 | # * args from the command line 167 | # * the main class name 168 | # * -classpath 169 | # * -D...appname settings 170 | # * --module-path (only if needed) 171 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 172 | 173 | # For Cygwin or MSYS, switch paths to Windows format before running java 174 | if "$cygwin" || "$msys" ; then 175 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 176 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 177 | 178 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 179 | 180 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 181 | for arg do 182 | if 183 | case $arg in #( 184 | -*) false ;; # don't mess with options #( 185 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 186 | [ -e "$t" ] ;; #( 187 | *) false ;; 188 | esac 189 | then 190 | arg=$( cygpath --path --ignore --mixed "$arg" ) 191 | fi 192 | # Roll the args list around exactly as many times as the number of 193 | # args, so each arg winds up back in the position where it started, but 194 | # possibly modified. 195 | # 196 | # NB: a `for` loop captures its iteration list before it begins, so 197 | # changing the positional parameters here affects neither the number of 198 | # iterations, nor the values presented in `arg`. 199 | shift # remove old arg 200 | set -- "$@" "$arg" # push replacement arg 201 | done 202 | fi 203 | 204 | 205 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 206 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 207 | 208 | # Collect all arguments for the java command: 209 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 210 | # and any embedded shellness will be escaped. 211 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 212 | # treated as '${Hostname}' itself on the command line. 213 | 214 | set -- \ 215 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 216 | -classpath "$CLASSPATH" \ 217 | org.gradle.wrapper.GradleWrapperMain \ 218 | "$@" 219 | 220 | # Stop when "xargs" is not available. 221 | if ! command -v xargs >/dev/null 2>&1 222 | then 223 | die "xargs is not available" 224 | fi 225 | 226 | # Use "xargs" to parse quoted args. 227 | # 228 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 229 | # 230 | # In Bash we could simply go: 231 | # 232 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 233 | # set -- "${ARGS[@]}" "$@" 234 | # 235 | # but POSIX shell has neither arrays nor command substitution, so instead we 236 | # post-process each arg (as a line of input to sed) to backslash-escape any 237 | # character that might be a shell metacharacter, then use eval to reverse 238 | # that process (while maintaining the separation between arguments), and wrap 239 | # the whole thing up as a single "set" statement. 240 | # 241 | # This will of course break if any of these variables contains a newline or 242 | # an unmatched quote. 243 | # 244 | 245 | eval "set -- $( 246 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 247 | xargs -n1 | 248 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 249 | tr '\n' ' ' 250 | )" '"$@"' 251 | 252 | exec "$JAVACMD" "$@" 253 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | extends: [ 4 | "local>hivemq/renovate-config:default.json5", 5 | ], 6 | addLabels: [ 7 | "tooling-and-extensions-coordination", 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "hivemq-mqtt-message-log-extension" 2 | -------------------------------------------------------------------------------- /src/hivemq-extension/conf/examples/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 10 | false 11 | true 12 | 13 | 14 | false 15 | false 16 | 17 | true 18 | true 19 | true 20 | true 21 | true 22 | true 23 | true 24 | true 25 | true 26 | true 27 | true 28 | true 29 | true 30 | true 31 | true 32 | true 33 | true 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/integrationTest/java/com/hivemq/extensions/log/FullConfigIT.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log; 17 | 18 | import com.hivemq.client.mqtt.datatypes.MqttQos; 19 | import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; 20 | import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; 21 | import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5PayloadFormatIndicator; 22 | import io.github.sgtsilvio.gradle.oci.junit.jupiter.OciImages; 23 | import org.jetbrains.annotations.NotNull; 24 | import org.junit.jupiter.api.Test; 25 | import org.testcontainers.hivemq.HiveMQContainer; 26 | import org.testcontainers.junit.jupiter.Container; 27 | import org.testcontainers.junit.jupiter.Testcontainers; 28 | import org.testcontainers.utility.MountableFile; 29 | 30 | import java.nio.charset.StandardCharsets; 31 | 32 | import static org.awaitility.Awaitility.await; 33 | 34 | /** 35 | * @since 1.1.3 36 | */ 37 | @Testcontainers 38 | public class FullConfigIT { 39 | 40 | @Container 41 | final @NotNull HiveMQContainer hivemq = 42 | new HiveMQContainer(OciImages.getImageName("hivemq/extensions/hivemq-mqtt-message-log-extension") 43 | .asCompatibleSubstituteFor("hivemq/hivemq4")) // 44 | .withCopyToContainer(MountableFile.forClasspathResource("fullConfig.properties"), 45 | "/opt/hivemq/extensions/hivemq-mqtt-message-log-extension/mqttMessageLog.properties") 46 | .withLogConsumer(outputFrame -> System.out.print("HiveMQ: " + outputFrame.getUtf8String())); 47 | 48 | @Test 49 | void test() { 50 | final Mqtt5BlockingClient client = Mqtt5Client.builder() 51 | .identifier("test-client") 52 | .serverHost(hivemq.getHost()) 53 | .serverPort(hivemq.getMqttPort()) 54 | .buildBlocking(); 55 | 56 | client.connectWith() 57 | .willPublish() 58 | .topic("will") 59 | .qos(MqttQos.EXACTLY_ONCE) 60 | .payload("willPayload".getBytes(StandardCharsets.UTF_8)) 61 | .contentType("text/plain") 62 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 63 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 64 | .responseTopic("willResponse") 65 | .retain(false) 66 | .messageExpiryInterval(10_000) 67 | .userProperties() 68 | .add("willProperty", "willValue") 69 | .applyUserProperties() 70 | .delayInterval(50_000) 71 | .applyWillPublish() 72 | .send(); 73 | await().until(() -> hivemq.getLogs() 74 | .contains( 75 | "Received CONNECT from client 'test-client': Protocol version: 'V_5', Clean Start: 'true', Session Expiry Interval: '0', Keep Alive: '60', Maximum Packet Size: '268435460', Receive Maximum: '65535', Topic Alias Maximum: '0', Request Problem Information: 'true', Request Response Information: 'false', Username: 'null', Password: 'null', Auth Method: 'null', Auth Data (Base64): 'null', User Properties: 'null', Will: { Topic: 'will', Payload: 'willPayload', QoS: '2', Retained: 'false', Message Expiry Interval: '10000', Duplicate Delivery: 'false', Correlation Data: 'willCorrelationData', Response Topic: 'willResponse', Content Type: 'text/plain', Payload Format Indicator: 'UTF_8', Subscription Identifiers: '[]', User Properties: [Name: 'willProperty', Value: 'willValue'], Will Delay: '50000' }")); 76 | await().until(() -> hivemq.getLogs() 77 | .contains( 78 | "Sent CONNACK to client 'test-client': Reason Code: 'SUCCESS', Session Present: 'false', Session Expiry Interval: 'null', Assigned ClientId 'null', Maximum QoS: 'EXACTLY_ONCE', Maximum Packet Size: '268435460', Receive Maximum: '10', Topic Alias Maximum: '5', Reason String: 'null', Response Information: 'null', Server Keep Alive: 'null', Server Reference: 'null', Shared Subscription Available: 'true', Wildcards Available: 'true', Retain Available: 'true', Subscription Identifiers Available: 'true', Auth Method: 'null', Auth Data (Base64): 'null', User Properties: 'null'")); 79 | 80 | client.subscribeWith().topicFilter("#").send(); 81 | await().until(() -> hivemq.getLogs() 82 | .contains( 83 | "Received SUBSCRIBE from client 'test-client': Topics: { [Topic: '#', QoS: '2', Retain As Published: 'false', No Local: 'false', Retain Handling: 'SEND'] }, Subscription Identifier: '1', User Properties: 'null'")); 84 | await().until(() -> hivemq.getLogs() 85 | .contains( 86 | "Sent SUBACK to client 'test-client': Suback Reason Codes: { [Reason Code: 'GRANTED_QOS_2'] }, Reason String: 'null', User Properties: 'null'")); 87 | 88 | client.publishWith() 89 | .topic("publish") 90 | .qos(MqttQos.EXACTLY_ONCE) 91 | .payload("payload1".getBytes(StandardCharsets.UTF_8)) 92 | .contentType("text/plain") 93 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 94 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 95 | .responseTopic("publishResponse") 96 | .retain(false) 97 | .messageExpiryInterval(10_000) 98 | .userProperties() 99 | .add("publishProperty", "publishValue") 100 | .applyUserProperties() 101 | .send(); 102 | await().until(() -> hivemq.getLogs() 103 | .contains( 104 | "Received PUBLISH from client 'test-client' for topic 'publish': Payload: 'payload1', QoS: '2', Retained: 'false', Message Expiry Interval: '10000', Duplicate Delivery: 'false', Correlation Data: 'willCorrelationData', Response Topic: 'publishResponse', Content Type: 'text/plain', Payload Format Indicator: 'UTF_8', Subscription Identifiers: '[]', User Properties: [Name: 'publishProperty', Value: 'publishValue']")); 105 | await().until(() -> hivemq.getLogs() 106 | .contains( 107 | "Sent PUBREC to client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 108 | await().until(() -> hivemq.getLogs() 109 | .contains( 110 | "Received PUBREL from client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 111 | await().until(() -> hivemq.getLogs() 112 | .contains( 113 | "Sent PUBCOMP to client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 114 | 115 | await().until(() -> hivemq.getLogs() 116 | .contains( 117 | "Sent PUBLISH to client 'test-client' on topic 'publish': Payload: 'payload1', QoS: '2', Retained: 'false', Message Expiry Interval: '10000', Duplicate Delivery: 'false', Correlation Data: 'willCorrelationData', Response Topic: 'publishResponse', Content Type: 'text/plain', Payload Format Indicator: 'UTF_8', Subscription Identifiers: '[1]', User Properties: [Name: 'publishProperty', Value: 'publishValue']")); 118 | await().until(() -> hivemq.getLogs() 119 | .contains( 120 | "Received PUBREC from client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 121 | await().until(() -> hivemq.getLogs() 122 | .contains( 123 | "Sent PUBREL to client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 124 | await().until(() -> hivemq.getLogs() 125 | .contains( 126 | "Received PUBCOMP from client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 127 | 128 | client.publishWith() 129 | .topic("publish") 130 | .qos(MqttQos.AT_LEAST_ONCE) 131 | .payload("payload2".getBytes(StandardCharsets.UTF_8)) 132 | .contentType("text/plain") 133 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 134 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 135 | .responseTopic("publishResponse") 136 | .retain(false) 137 | .messageExpiryInterval(10_000) 138 | .userProperties() 139 | .add("publishProperty", "publishValue") 140 | .applyUserProperties() 141 | .send(); 142 | await().until(() -> hivemq.getLogs() 143 | .contains( 144 | "Received PUBLISH from client 'test-client' for topic 'publish': Payload: 'payload2', QoS: '1', Retained: 'false', Message Expiry Interval: '10000', Duplicate Delivery: 'false', Correlation Data: 'willCorrelationData', Response Topic: 'publishResponse', Content Type: 'text/plain', Payload Format Indicator: 'UTF_8', Subscription Identifiers: '[]', User Properties: [Name: 'publishProperty', Value: 'publishValue']")); 145 | await().until(() -> hivemq.getLogs() 146 | .contains( 147 | "Sent PUBACK to client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 148 | await().until(() -> hivemq.getLogs() 149 | .contains( 150 | "Sent PUBLISH to client 'test-client' on topic 'publish': Payload: 'payload2', QoS: '1', Retained: 'false', Message Expiry Interval: '10000', Duplicate Delivery: 'false', Correlation Data: 'willCorrelationData', Response Topic: 'publishResponse', Content Type: 'text/plain', Payload Format Indicator: 'UTF_8', Subscription Identifiers: '[1]', User Properties: [Name: 'publishProperty', Value: 'publishValue']")); 151 | await().until(() -> hivemq.getLogs() 152 | .contains( 153 | "Received PUBACK from client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 154 | 155 | client.unsubscribeWith().topicFilter("#").send(); 156 | await().until(() -> hivemq.getLogs() 157 | .contains( 158 | "Received UNSUBSCRIBE from client 'test-client': Topics: { [Topic: '#'] }, User Properties: 'null'")); 159 | await().until(() -> hivemq.getLogs() 160 | .contains( 161 | "Sent UNSUBACK to client 'test-client': Unsuback Reason Codes: { [Reason Code: 'SUCCESS'] }, Reason String: 'null', User Properties: 'null'")); 162 | 163 | client.disconnect(); 164 | await().until(() -> hivemq.getLogs() 165 | .contains( 166 | "Received DISCONNECT from client 'test-client': Reason Code: 'NORMAL_DISCONNECTION', Reason String: 'null', Server Reference: 'null', Session Expiry: 'null', User Properties: 'null'")); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/integrationTest/java/com/hivemq/extensions/log/FullConfigNoPayloadNoVerboseIT.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log; 17 | 18 | import com.hivemq.client.mqtt.datatypes.MqttQos; 19 | import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; 20 | import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; 21 | import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5PayloadFormatIndicator; 22 | import io.github.sgtsilvio.gradle.oci.junit.jupiter.OciImages; 23 | import org.jetbrains.annotations.NotNull; 24 | import org.junit.jupiter.api.Test; 25 | import org.testcontainers.hivemq.HiveMQContainer; 26 | import org.testcontainers.junit.jupiter.Container; 27 | import org.testcontainers.junit.jupiter.Testcontainers; 28 | import org.testcontainers.utility.MountableFile; 29 | 30 | import java.nio.charset.StandardCharsets; 31 | 32 | import static org.awaitility.Awaitility.await; 33 | import static org.junit.jupiter.api.Assertions.assertFalse; 34 | 35 | /** 36 | * @since 1.1.6 37 | */ 38 | @Testcontainers 39 | public class FullConfigNoPayloadNoVerboseIT { 40 | 41 | @Container 42 | final @NotNull HiveMQContainer hivemq = 43 | new HiveMQContainer(OciImages.getImageName("hivemq/extensions/hivemq-mqtt-message-log-extension") 44 | .asCompatibleSubstituteFor("hivemq/hivemq4")) // 45 | .withCopyToContainer(MountableFile.forClasspathResource("fullConfigNoPayloadNoVerbose.properties"), 46 | "/opt/hivemq/extensions/hivemq-mqtt-message-log-extension/mqttMessageLog.properties") 47 | .withLogConsumer(outputFrame -> System.out.print("HiveMQ: " + outputFrame.getUtf8String())); 48 | 49 | @Test 50 | void test() { 51 | final Mqtt5BlockingClient client = Mqtt5Client.builder() 52 | .identifier("test-client") 53 | .serverHost(hivemq.getHost()) 54 | .serverPort(hivemq.getMqttPort()) 55 | .buildBlocking(); 56 | 57 | client.connectWith() 58 | .willPublish() 59 | .topic("will") 60 | .qos(MqttQos.EXACTLY_ONCE) 61 | .payload("willPayload".getBytes(StandardCharsets.UTF_8)) 62 | .contentType("text/plain") 63 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 64 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 65 | .responseTopic("willResponse") 66 | .retain(false) 67 | .messageExpiryInterval(10_000) 68 | .userProperties() 69 | .add("willProperty", "willValue") 70 | .applyUserProperties() 71 | .delayInterval(50_000) 72 | .applyWillPublish() 73 | .send(); 74 | await().until(() -> hivemq.getLogs() 75 | .contains( 76 | "Received CONNECT from client 'test-client': Protocol version: 'V_5', Clean Start: 'true', Session Expiry Interval: '0'")); 77 | await().until(() -> hivemq.getLogs() 78 | .contains("Sent CONNACK to client 'test-client': Reason Code: 'SUCCESS', Session Present: 'false'")); 79 | 80 | client.subscribeWith().topicFilter("#").send(); 81 | await().until(() -> hivemq.getLogs() 82 | .contains("Received SUBSCRIBE from client 'test-client': Topics: { [Topic: '#', QoS: '2'] }")); 83 | await().until(() -> hivemq.getLogs() 84 | .contains("Sent SUBACK to client 'test-client': Suback Reason Codes: { [Reason Code: 'GRANTED_QOS_2'] }")); 85 | 86 | client.publishWith() 87 | .topic("publish") 88 | .qos(MqttQos.EXACTLY_ONCE) 89 | .payload("payload1".getBytes(StandardCharsets.UTF_8)) 90 | .contentType("text/plain") 91 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 92 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 93 | .responseTopic("publishResponse") 94 | .retain(false) 95 | .messageExpiryInterval(10_000) 96 | .userProperties() 97 | .add("publishProperty", "publishValue") 98 | .applyUserProperties() 99 | .send(); 100 | await().until(() -> hivemq.getLogs() 101 | .contains("Received PUBLISH from client 'test-client' for topic 'publish': QoS: '2', Retained: 'false'")); 102 | await().until(() -> hivemq.getLogs().contains("Sent PUBREC to client 'test-client': Reason Code: 'SUCCESS'")); 103 | await().until(() -> hivemq.getLogs() 104 | .contains("Received PUBREL from client 'test-client': Reason Code: 'SUCCESS'")); 105 | await().until(() -> hivemq.getLogs().contains("Sent PUBCOMP to client 'test-client': Reason Code: 'SUCCESS'")); 106 | 107 | await().until(() -> hivemq.getLogs() 108 | .contains("Sent PUBLISH to client 'test-client' on topic 'publish': QoS: '2', Retained: 'false'")); 109 | await().until(() -> hivemq.getLogs() 110 | .contains("Received PUBREC from client 'test-client': Reason Code: 'SUCCESS'")); 111 | await().until(() -> hivemq.getLogs().contains("Sent PUBREL to client 'test-client': Reason Code: 'SUCCESS'")); 112 | await().until(() -> hivemq.getLogs() 113 | .contains("Received PUBCOMP from client 'test-client': Reason Code: 'SUCCESS'")); 114 | 115 | client.publishWith() 116 | .topic("publish") 117 | .qos(MqttQos.AT_LEAST_ONCE) 118 | .payload("payload2".getBytes(StandardCharsets.UTF_8)) 119 | .contentType("text/plain") 120 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 121 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 122 | .responseTopic("publishResponse") 123 | .retain(false) 124 | .messageExpiryInterval(10_000) 125 | .userProperties() 126 | .add("publishProperty", "publishValue") 127 | .applyUserProperties() 128 | .send(); 129 | await().until(() -> hivemq.getLogs() 130 | .contains("Received PUBLISH from client 'test-client' for topic 'publish': QoS: '1', Retained: 'false'")); 131 | await().until(() -> hivemq.getLogs().contains("Sent PUBACK to client 'test-client': Reason Code: 'SUCCESS'")); 132 | await().until(() -> hivemq.getLogs() 133 | .contains("Sent PUBLISH to client 'test-client' on topic 'publish': QoS: '1', Retained: 'false'")); 134 | await().until(() -> hivemq.getLogs() 135 | .contains("Received PUBACK from client 'test-client': Reason Code: 'SUCCESS'")); 136 | 137 | client.unsubscribeWith().topicFilter("#").send(); 138 | await().until(() -> hivemq.getLogs() 139 | .contains("Received UNSUBSCRIBE from client 'test-client': Topics: { [Topic: '#'] }")); 140 | await().until(() -> hivemq.getLogs() 141 | .contains("Sent UNSUBACK to client 'test-client': Unsuback Reason Codes: { [Reason Code: 'SUCCESS'] }")); 142 | 143 | client.disconnect(); 144 | await().until(() -> hivemq.getLogs() 145 | .contains("Received DISCONNECT from client 'test-client': Reason Code: 'NORMAL_DISCONNECTION'")); 146 | 147 | assertFalse(hivemq.getLogs().contains("Payload: 'payload1'")); 148 | assertFalse(hivemq.getLogs().contains("Payload: 'payload2'")); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/integrationTest/java/com/hivemq/extensions/log/FullConfigNoVerboseIT.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log; 17 | 18 | import com.hivemq.client.mqtt.datatypes.MqttQos; 19 | import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; 20 | import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; 21 | import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5PayloadFormatIndicator; 22 | import io.github.sgtsilvio.gradle.oci.junit.jupiter.OciImages; 23 | import org.jetbrains.annotations.NotNull; 24 | import org.junit.jupiter.api.Test; 25 | import org.testcontainers.hivemq.HiveMQContainer; 26 | import org.testcontainers.junit.jupiter.Container; 27 | import org.testcontainers.junit.jupiter.Testcontainers; 28 | import org.testcontainers.utility.MountableFile; 29 | 30 | import java.nio.charset.StandardCharsets; 31 | 32 | import static org.awaitility.Awaitility.await; 33 | import static org.junit.jupiter.api.Assertions.assertTrue; 34 | 35 | /** 36 | * @since 1.1.6 37 | */ 38 | @Testcontainers 39 | public class FullConfigNoVerboseIT { 40 | 41 | @Container 42 | final @NotNull HiveMQContainer hivemq = 43 | new HiveMQContainer(OciImages.getImageName("hivemq/extensions/hivemq-mqtt-message-log-extension") 44 | .asCompatibleSubstituteFor("hivemq/hivemq4")) // 45 | .withCopyToContainer(MountableFile.forClasspathResource("fullConfigNoVerbose.properties"), 46 | "/opt/hivemq/extensions/hivemq-mqtt-message-log-extension/mqttMessageLog.properties") 47 | .withLogConsumer(outputFrame -> System.out.print("HiveMQ: " + outputFrame.getUtf8String())); 48 | 49 | @Test 50 | void test() { 51 | final Mqtt5BlockingClient client = Mqtt5Client.builder() 52 | .identifier("test-client") 53 | .serverHost(hivemq.getHost()) 54 | .serverPort(hivemq.getMqttPort()) 55 | .buildBlocking(); 56 | 57 | client.connectWith() 58 | .willPublish() 59 | .topic("will") 60 | .qos(MqttQos.EXACTLY_ONCE) 61 | .payload("willPayload".getBytes(StandardCharsets.UTF_8)) 62 | .contentType("text/plain") 63 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 64 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 65 | .responseTopic("willResponse") 66 | .retain(false) 67 | .messageExpiryInterval(10_000) 68 | .userProperties() 69 | .add("willProperty", "willValue") 70 | .applyUserProperties() 71 | .delayInterval(50_000) 72 | .applyWillPublish() 73 | .send(); 74 | await().until(() -> hivemq.getLogs() 75 | .contains( 76 | "Received CONNECT from client 'test-client': Protocol version: 'V_5', Clean Start: 'true', Session Expiry Interval: '0'")); 77 | await().until(() -> hivemq.getLogs() 78 | .contains("Sent CONNACK to client 'test-client': Reason Code: 'SUCCESS', Session Present: 'false'")); 79 | 80 | client.subscribeWith().topicFilter("#").send(); 81 | await().until(() -> hivemq.getLogs() 82 | .contains("Received SUBSCRIBE from client 'test-client': Topics: { [Topic: '#', QoS: '2'] }")); 83 | await().until(() -> hivemq.getLogs() 84 | .contains("Sent SUBACK to client 'test-client': Suback Reason Codes: { [Reason Code: 'GRANTED_QOS_2'] }")); 85 | 86 | client.publishWith() 87 | .topic("publish") 88 | .qos(MqttQos.EXACTLY_ONCE) 89 | .payload("payload1".getBytes(StandardCharsets.UTF_8)) 90 | .contentType("text/plain") 91 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 92 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 93 | .responseTopic("publishResponse") 94 | .retain(false) 95 | .messageExpiryInterval(10_000) 96 | .userProperties() 97 | .add("publishProperty", "publishValue") 98 | .applyUserProperties() 99 | .send(); 100 | await().until(() -> hivemq.getLogs() 101 | .contains( 102 | "Received PUBLISH from client 'test-client' for topic 'publish': Payload: 'payload1', QoS: '2', Retained: 'false'")); 103 | await().until(() -> hivemq.getLogs().contains("Sent PUBREC to client 'test-client': Reason Code: 'SUCCESS'")); 104 | await().until(() -> hivemq.getLogs() 105 | .contains("Received PUBREL from client 'test-client': Reason Code: 'SUCCESS'")); 106 | await().until(() -> hivemq.getLogs().contains("Sent PUBCOMP to client 'test-client': Reason Code: 'SUCCESS'")); 107 | 108 | await().until(() -> hivemq.getLogs() 109 | .contains( 110 | "Sent PUBLISH to client 'test-client' on topic 'publish': Payload: 'payload1', QoS: '2', Retained: 'false'")); 111 | await().until(() -> hivemq.getLogs() 112 | .contains("Received PUBREC from client 'test-client': Reason Code: 'SUCCESS'")); 113 | await().until(() -> hivemq.getLogs().contains("Sent PUBREL to client 'test-client': Reason Code: 'SUCCESS'")); 114 | await().until(() -> hivemq.getLogs() 115 | .contains("Received PUBCOMP from client 'test-client': Reason Code: 'SUCCESS'")); 116 | 117 | client.publishWith() 118 | .topic("publish") 119 | .qos(MqttQos.AT_LEAST_ONCE) 120 | .payload("payload2".getBytes(StandardCharsets.UTF_8)) 121 | .contentType("text/plain") 122 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 123 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 124 | .responseTopic("publishResponse") 125 | .retain(false) 126 | .messageExpiryInterval(10_000) 127 | .userProperties() 128 | .add("publishProperty", "publishValue") 129 | .applyUserProperties() 130 | .send(); 131 | await().until(() -> hivemq.getLogs() 132 | .contains( 133 | "Received PUBLISH from client 'test-client' for topic 'publish': Payload: 'payload2', QoS: '1', Retained: 'false'")); 134 | await().until(() -> hivemq.getLogs().contains("Sent PUBACK to client 'test-client': Reason Code: 'SUCCESS'")); 135 | await().until(() -> hivemq.getLogs() 136 | .contains( 137 | "Sent PUBLISH to client 'test-client' on topic 'publish': Payload: 'payload2', QoS: '1', Retained: 'false'")); 138 | await().until(() -> hivemq.getLogs() 139 | .contains("Received PUBACK from client 'test-client': Reason Code: 'SUCCESS'")); 140 | 141 | client.unsubscribeWith().topicFilter("#").send(); 142 | await().until(() -> hivemq.getLogs() 143 | .contains("Received UNSUBSCRIBE from client 'test-client': Topics: { [Topic: '#'] }")); 144 | await().until(() -> hivemq.getLogs() 145 | .contains("Sent UNSUBACK to client 'test-client': Unsuback Reason Codes: { [Reason Code: 'SUCCESS'] }")); 146 | 147 | client.disconnect(); 148 | await().until(() -> hivemq.getLogs() 149 | .contains("Received DISCONNECT from client 'test-client': Reason Code: 'NORMAL_DISCONNECTION'")); 150 | 151 | assertTrue(hivemq.getLogs().contains("Payload: 'payload1'")); 152 | assertTrue(hivemq.getLogs().contains("Payload: 'payload2'")); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/integrationTest/java/com/hivemq/extensions/log/FullConfigXmlIT.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log; 17 | 18 | import com.hivemq.client.mqtt.datatypes.MqttQos; 19 | import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; 20 | import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; 21 | import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5PayloadFormatIndicator; 22 | import io.github.sgtsilvio.gradle.oci.junit.jupiter.OciImages; 23 | import org.jetbrains.annotations.NotNull; 24 | import org.junit.jupiter.api.Test; 25 | import org.testcontainers.hivemq.HiveMQContainer; 26 | import org.testcontainers.junit.jupiter.Container; 27 | import org.testcontainers.junit.jupiter.Testcontainers; 28 | import org.testcontainers.utility.MountableFile; 29 | 30 | import java.nio.charset.StandardCharsets; 31 | 32 | import static org.awaitility.Awaitility.await; 33 | 34 | /** 35 | * @since 1.2.0 36 | */ 37 | @Testcontainers 38 | public class FullConfigXmlIT { 39 | 40 | @Container 41 | final @NotNull HiveMQContainer hivemq = 42 | new HiveMQContainer(OciImages.getImageName("hivemq/extensions/hivemq-mqtt-message-log-extension") 43 | .asCompatibleSubstituteFor("hivemq/hivemq4")) // 44 | .withCopyToContainer(MountableFile.forClasspathResource("fullConfig.xml"), 45 | "/opt/hivemq/extensions/hivemq-mqtt-message-log-extension/conf/config.xml") 46 | .withLogConsumer(outputFrame -> System.out.print("HiveMQ: " + outputFrame.getUtf8String())); 47 | 48 | @Test 49 | void test() { 50 | final Mqtt5BlockingClient client = Mqtt5Client.builder() 51 | .identifier("test-client") 52 | .serverHost(hivemq.getHost()) 53 | .serverPort(hivemq.getMqttPort()) 54 | .buildBlocking(); 55 | 56 | client.connectWith() 57 | .willPublish() 58 | .topic("will") 59 | .qos(MqttQos.EXACTLY_ONCE) 60 | .payload("willPayload".getBytes(StandardCharsets.UTF_8)) 61 | .contentType("text/plain") 62 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 63 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 64 | .responseTopic("willResponse") 65 | .retain(false) 66 | .messageExpiryInterval(10_000) 67 | .userProperties() 68 | .add("willProperty", "willValue") 69 | .applyUserProperties() 70 | .delayInterval(50_000) 71 | .applyWillPublish() 72 | .send(); 73 | await().until(() -> hivemq.getLogs() 74 | .contains( 75 | "Received CONNECT from client 'test-client': Protocol version: 'V_5', Clean Start: 'true', Session Expiry Interval: '0', Keep Alive: '60', Maximum Packet Size: '268435460', Receive Maximum: '65535', Topic Alias Maximum: '0', Request Problem Information: 'true', Request Response Information: 'false', Username: 'null', Password: 'null', Auth Method: 'null', Auth Data (Base64): 'null', User Properties: 'null', Will: { Topic: 'will', Payload: 'willPayload', QoS: '2', Retained: 'false', Message Expiry Interval: '10000', Duplicate Delivery: 'false', Correlation Data: 'willCorrelationData', Response Topic: 'willResponse', Content Type: 'text/plain', Payload Format Indicator: 'UTF_8', Subscription Identifiers: '[]', User Properties: [Name: 'willProperty', Value: 'willValue'], Will Delay: '50000' }")); 76 | await().until(() -> hivemq.getLogs() 77 | .contains( 78 | "Sent CONNACK to client 'test-client': Reason Code: 'SUCCESS', Session Present: 'false', Session Expiry Interval: 'null', Assigned ClientId 'null', Maximum QoS: 'EXACTLY_ONCE', Maximum Packet Size: '268435460', Receive Maximum: '10', Topic Alias Maximum: '5', Reason String: 'null', Response Information: 'null', Server Keep Alive: 'null', Server Reference: 'null', Shared Subscription Available: 'true', Wildcards Available: 'true', Retain Available: 'true', Subscription Identifiers Available: 'true', Auth Method: 'null', Auth Data (Base64): 'null', User Properties: 'null'")); 79 | 80 | client.subscribeWith().topicFilter("#").send(); 81 | await().until(() -> hivemq.getLogs() 82 | .contains( 83 | "Received SUBSCRIBE from client 'test-client': Topics: { [Topic: '#', QoS: '2', Retain As Published: 'false', No Local: 'false', Retain Handling: 'SEND'] }, Subscription Identifier: '1', User Properties: 'null'")); 84 | await().until(() -> hivemq.getLogs() 85 | .contains( 86 | "Sent SUBACK to client 'test-client': Suback Reason Codes: { [Reason Code: 'GRANTED_QOS_2'] }, Reason String: 'null', User Properties: 'null'")); 87 | 88 | client.publishWith() 89 | .topic("publish") 90 | .qos(MqttQos.EXACTLY_ONCE) 91 | .payload("payload1".getBytes(StandardCharsets.UTF_8)) 92 | .contentType("text/plain") 93 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 94 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 95 | .responseTopic("publishResponse") 96 | .retain(false) 97 | .messageExpiryInterval(10_000) 98 | .userProperties() 99 | .add("publishProperty", "publishValue") 100 | .applyUserProperties() 101 | .send(); 102 | await().until(() -> hivemq.getLogs() 103 | .contains( 104 | "Received PUBLISH from client 'test-client' for topic 'publish': Payload: 'payload1', QoS: '2', Retained: 'false', Message Expiry Interval: '10000', Duplicate Delivery: 'false', Correlation Data: 'willCorrelationData', Response Topic: 'publishResponse', Content Type: 'text/plain', Payload Format Indicator: 'UTF_8', Subscription Identifiers: '[]', User Properties: [Name: 'publishProperty', Value: 'publishValue']")); 105 | await().until(() -> hivemq.getLogs() 106 | .contains( 107 | "Sent PUBREC to client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 108 | await().until(() -> hivemq.getLogs() 109 | .contains( 110 | "Received PUBREL from client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 111 | await().until(() -> hivemq.getLogs() 112 | .contains( 113 | "Sent PUBCOMP to client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 114 | 115 | await().until(() -> hivemq.getLogs() 116 | .contains( 117 | "Sent PUBLISH to client 'test-client' on topic 'publish': Payload: 'payload1', QoS: '2', Retained: 'false', Message Expiry Interval: '10000', Duplicate Delivery: 'false', Correlation Data: 'willCorrelationData', Response Topic: 'publishResponse', Content Type: 'text/plain', Payload Format Indicator: 'UTF_8', Subscription Identifiers: '[1]', User Properties: [Name: 'publishProperty', Value: 'publishValue']")); 118 | await().until(() -> hivemq.getLogs() 119 | .contains( 120 | "Received PUBREC from client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 121 | await().until(() -> hivemq.getLogs() 122 | .contains( 123 | "Sent PUBREL to client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 124 | await().until(() -> hivemq.getLogs() 125 | .contains( 126 | "Received PUBCOMP from client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 127 | 128 | client.publishWith() 129 | .topic("publish") 130 | .qos(MqttQos.AT_LEAST_ONCE) 131 | .payload("payload2".getBytes(StandardCharsets.UTF_8)) 132 | .contentType("text/plain") 133 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 134 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 135 | .responseTopic("publishResponse") 136 | .retain(false) 137 | .messageExpiryInterval(10_000) 138 | .userProperties() 139 | .add("publishProperty", "publishValue") 140 | .applyUserProperties() 141 | .send(); 142 | await().until(() -> hivemq.getLogs() 143 | .contains( 144 | "Received PUBLISH from client 'test-client' for topic 'publish': Payload: 'payload2', QoS: '1', Retained: 'false', Message Expiry Interval: '10000', Duplicate Delivery: 'false', Correlation Data: 'willCorrelationData', Response Topic: 'publishResponse', Content Type: 'text/plain', Payload Format Indicator: 'UTF_8', Subscription Identifiers: '[]', User Properties: [Name: 'publishProperty', Value: 'publishValue']")); 145 | await().until(() -> hivemq.getLogs() 146 | .contains( 147 | "Sent PUBACK to client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 148 | await().until(() -> hivemq.getLogs() 149 | .contains( 150 | "Sent PUBLISH to client 'test-client' on topic 'publish': Payload: 'payload2', QoS: '1', Retained: 'false', Message Expiry Interval: '10000', Duplicate Delivery: 'false', Correlation Data: 'willCorrelationData', Response Topic: 'publishResponse', Content Type: 'text/plain', Payload Format Indicator: 'UTF_8', Subscription Identifiers: '[1]', User Properties: [Name: 'publishProperty', Value: 'publishValue']")); 151 | await().until(() -> hivemq.getLogs() 152 | .contains( 153 | "Received PUBACK from client 'test-client': Reason Code: 'SUCCESS', Reason String: 'null', User Properties: 'null'")); 154 | 155 | client.unsubscribeWith().topicFilter("#").send(); 156 | await().until(() -> hivemq.getLogs() 157 | .contains( 158 | "Received UNSUBSCRIBE from client 'test-client': Topics: { [Topic: '#'] }, User Properties: 'null'")); 159 | await().until(() -> hivemq.getLogs() 160 | .contains( 161 | "Sent UNSUBACK to client 'test-client': Unsuback Reason Codes: { [Reason Code: 'SUCCESS'] }, Reason String: 'null', User Properties: 'null'")); 162 | 163 | client.disconnect(); 164 | await().until(() -> hivemq.getLogs() 165 | .contains( 166 | "Received DISCONNECT from client 'test-client': Reason Code: 'NORMAL_DISCONNECTION', Reason String: 'null', Server Reference: 'null', Session Expiry: 'null', User Properties: 'null'")); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/integrationTest/java/com/hivemq/extensions/log/FullConfigXmlNoPayloadNoVerboseIT.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log; 17 | 18 | import com.hivemq.client.mqtt.datatypes.MqttQos; 19 | import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; 20 | import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; 21 | import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5PayloadFormatIndicator; 22 | import io.github.sgtsilvio.gradle.oci.junit.jupiter.OciImages; 23 | import org.jetbrains.annotations.NotNull; 24 | import org.junit.jupiter.api.Test; 25 | import org.testcontainers.hivemq.HiveMQContainer; 26 | import org.testcontainers.junit.jupiter.Container; 27 | import org.testcontainers.junit.jupiter.Testcontainers; 28 | import org.testcontainers.utility.MountableFile; 29 | 30 | import java.nio.charset.StandardCharsets; 31 | 32 | import static org.awaitility.Awaitility.await; 33 | import static org.junit.jupiter.api.Assertions.assertFalse; 34 | 35 | /** 36 | * @since 1.2.0 37 | */ 38 | @Testcontainers 39 | public class FullConfigXmlNoPayloadNoVerboseIT { 40 | 41 | @Container 42 | final @NotNull HiveMQContainer hivemq = 43 | new HiveMQContainer(OciImages.getImageName("hivemq/extensions/hivemq-mqtt-message-log-extension") 44 | .asCompatibleSubstituteFor("hivemq/hivemq4")) // 45 | .withCopyToContainer(MountableFile.forClasspathResource("fullConfigNoPayloadNoVerbose.xml"), 46 | "/opt/hivemq/extensions/hivemq-mqtt-message-log-extension/conf/config.xml") 47 | .withLogConsumer(outputFrame -> System.out.print("HiveMQ: " + outputFrame.getUtf8String())); 48 | 49 | @Test 50 | void test() { 51 | final Mqtt5BlockingClient client = Mqtt5Client.builder() 52 | .identifier("test-client") 53 | .serverHost(hivemq.getHost()) 54 | .serverPort(hivemq.getMqttPort()) 55 | .buildBlocking(); 56 | 57 | client.connectWith() 58 | .willPublish() 59 | .topic("will") 60 | .qos(MqttQos.EXACTLY_ONCE) 61 | .payload("willPayload".getBytes(StandardCharsets.UTF_8)) 62 | .contentType("text/plain") 63 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 64 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 65 | .responseTopic("willResponse") 66 | .retain(false) 67 | .messageExpiryInterval(10_000) 68 | .userProperties() 69 | .add("willProperty", "willValue") 70 | .applyUserProperties() 71 | .delayInterval(50_000) 72 | .applyWillPublish() 73 | .send(); 74 | await().until(() -> hivemq.getLogs() 75 | .contains( 76 | "Received CONNECT from client 'test-client': Protocol version: 'V_5', Clean Start: 'true', Session Expiry Interval: '0'")); 77 | await().until(() -> hivemq.getLogs() 78 | .contains("Sent CONNACK to client 'test-client': Reason Code: 'SUCCESS', Session Present: 'false'")); 79 | 80 | client.subscribeWith().topicFilter("#").send(); 81 | await().until(() -> hivemq.getLogs() 82 | .contains("Received SUBSCRIBE from client 'test-client': Topics: { [Topic: '#', QoS: '2'] }")); 83 | await().until(() -> hivemq.getLogs() 84 | .contains("Sent SUBACK to client 'test-client': Suback Reason Codes: { [Reason Code: 'GRANTED_QOS_2'] }")); 85 | 86 | client.publishWith() 87 | .topic("publish") 88 | .qos(MqttQos.EXACTLY_ONCE) 89 | .payload("payload1".getBytes(StandardCharsets.UTF_8)) 90 | .contentType("text/plain") 91 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 92 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 93 | .responseTopic("publishResponse") 94 | .retain(false) 95 | .messageExpiryInterval(10_000) 96 | .userProperties() 97 | .add("publishProperty", "publishValue") 98 | .applyUserProperties() 99 | .send(); 100 | await().until(() -> hivemq.getLogs() 101 | .contains("Received PUBLISH from client 'test-client' for topic 'publish': QoS: '2', Retained: 'false'")); 102 | await().until(() -> hivemq.getLogs().contains("Sent PUBREC to client 'test-client': Reason Code: 'SUCCESS'")); 103 | await().until(() -> hivemq.getLogs() 104 | .contains("Received PUBREL from client 'test-client': Reason Code: 'SUCCESS'")); 105 | await().until(() -> hivemq.getLogs().contains("Sent PUBCOMP to client 'test-client': Reason Code: 'SUCCESS'")); 106 | 107 | await().until(() -> hivemq.getLogs() 108 | .contains("Sent PUBLISH to client 'test-client' on topic 'publish': QoS: '2', Retained: 'false'")); 109 | await().until(() -> hivemq.getLogs() 110 | .contains("Received PUBREC from client 'test-client': Reason Code: 'SUCCESS'")); 111 | await().until(() -> hivemq.getLogs().contains("Sent PUBREL to client 'test-client': Reason Code: 'SUCCESS'")); 112 | await().until(() -> hivemq.getLogs() 113 | .contains("Received PUBCOMP from client 'test-client': Reason Code: 'SUCCESS'")); 114 | 115 | client.publishWith() 116 | .topic("publish") 117 | .qos(MqttQos.AT_LEAST_ONCE) 118 | .payload("payload2".getBytes(StandardCharsets.UTF_8)) 119 | .contentType("text/plain") 120 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 121 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 122 | .responseTopic("publishResponse") 123 | .retain(false) 124 | .messageExpiryInterval(10_000) 125 | .userProperties() 126 | .add("publishProperty", "publishValue") 127 | .applyUserProperties() 128 | .send(); 129 | await().until(() -> hivemq.getLogs() 130 | .contains("Received PUBLISH from client 'test-client' for topic 'publish': QoS: '1', Retained: 'false'")); 131 | await().until(() -> hivemq.getLogs().contains("Sent PUBACK to client 'test-client': Reason Code: 'SUCCESS'")); 132 | await().until(() -> hivemq.getLogs() 133 | .contains("Sent PUBLISH to client 'test-client' on topic 'publish': QoS: '1', Retained: 'false'")); 134 | await().until(() -> hivemq.getLogs() 135 | .contains("Received PUBACK from client 'test-client': Reason Code: 'SUCCESS'")); 136 | 137 | client.unsubscribeWith().topicFilter("#").send(); 138 | await().until(() -> hivemq.getLogs() 139 | .contains("Received UNSUBSCRIBE from client 'test-client': Topics: { [Topic: '#'] }")); 140 | await().until(() -> hivemq.getLogs() 141 | .contains("Sent UNSUBACK to client 'test-client': Unsuback Reason Codes: { [Reason Code: 'SUCCESS'] }")); 142 | 143 | client.disconnect(); 144 | await().until(() -> hivemq.getLogs() 145 | .contains("Received DISCONNECT from client 'test-client': Reason Code: 'NORMAL_DISCONNECTION'")); 146 | 147 | assertFalse(hivemq.getLogs().contains("Payload: 'payload1'")); 148 | assertFalse(hivemq.getLogs().contains("Payload: 'payload2'")); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/integrationTest/java/com/hivemq/extensions/log/FullConfigXmlNoVerboseIT.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log; 17 | 18 | import com.hivemq.client.mqtt.datatypes.MqttQos; 19 | import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; 20 | import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; 21 | import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5PayloadFormatIndicator; 22 | import io.github.sgtsilvio.gradle.oci.junit.jupiter.OciImages; 23 | import org.jetbrains.annotations.NotNull; 24 | import org.junit.jupiter.api.Test; 25 | import org.testcontainers.hivemq.HiveMQContainer; 26 | import org.testcontainers.junit.jupiter.Container; 27 | import org.testcontainers.junit.jupiter.Testcontainers; 28 | import org.testcontainers.utility.MountableFile; 29 | 30 | import java.nio.charset.StandardCharsets; 31 | 32 | import static org.awaitility.Awaitility.await; 33 | import static org.junit.jupiter.api.Assertions.assertTrue; 34 | 35 | /** 36 | * @since 1.2.0 37 | */ 38 | @Testcontainers 39 | public class FullConfigXmlNoVerboseIT { 40 | 41 | @Container 42 | final @NotNull HiveMQContainer hivemq = 43 | new HiveMQContainer(OciImages.getImageName("hivemq/extensions/hivemq-mqtt-message-log-extension") 44 | .asCompatibleSubstituteFor("hivemq/hivemq4")) // 45 | .withCopyToContainer(MountableFile.forClasspathResource("fullConfigNoVerbose.xml"), 46 | "/opt/hivemq/extensions/hivemq-mqtt-message-log-extension/conf/config.xml") 47 | .withLogConsumer(outputFrame -> System.out.print("HiveMQ: " + outputFrame.getUtf8String())); 48 | 49 | @Test 50 | void test() { 51 | final Mqtt5BlockingClient client = Mqtt5Client.builder() 52 | .identifier("test-client") 53 | .serverHost(hivemq.getHost()) 54 | .serverPort(hivemq.getMqttPort()) 55 | .buildBlocking(); 56 | 57 | client.connectWith() 58 | .willPublish() 59 | .topic("will") 60 | .qos(MqttQos.EXACTLY_ONCE) 61 | .payload("willPayload".getBytes(StandardCharsets.UTF_8)) 62 | .contentType("text/plain") 63 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 64 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 65 | .responseTopic("willResponse") 66 | .retain(false) 67 | .messageExpiryInterval(10_000) 68 | .userProperties() 69 | .add("willProperty", "willValue") 70 | .applyUserProperties() 71 | .delayInterval(50_000) 72 | .applyWillPublish() 73 | .send(); 74 | await().until(() -> hivemq.getLogs() 75 | .contains( 76 | "Received CONNECT from client 'test-client': Protocol version: 'V_5', Clean Start: 'true', Session Expiry Interval: '0'")); 77 | await().until(() -> hivemq.getLogs() 78 | .contains("Sent CONNACK to client 'test-client': Reason Code: 'SUCCESS', Session Present: 'false'")); 79 | 80 | client.subscribeWith().topicFilter("#").send(); 81 | await().until(() -> hivemq.getLogs() 82 | .contains("Received SUBSCRIBE from client 'test-client': Topics: { [Topic: '#', QoS: '2'] }")); 83 | await().until(() -> hivemq.getLogs() 84 | .contains("Sent SUBACK to client 'test-client': Suback Reason Codes: { [Reason Code: 'GRANTED_QOS_2'] }")); 85 | 86 | client.publishWith() 87 | .topic("publish") 88 | .qos(MqttQos.EXACTLY_ONCE) 89 | .payload("payload1".getBytes(StandardCharsets.UTF_8)) 90 | .contentType("text/plain") 91 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 92 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 93 | .responseTopic("publishResponse") 94 | .retain(false) 95 | .messageExpiryInterval(10_000) 96 | .userProperties() 97 | .add("publishProperty", "publishValue") 98 | .applyUserProperties() 99 | .send(); 100 | await().until(() -> hivemq.getLogs() 101 | .contains( 102 | "Received PUBLISH from client 'test-client' for topic 'publish': Payload: 'payload1', QoS: '2', Retained: 'false'")); 103 | await().until(() -> hivemq.getLogs().contains("Sent PUBREC to client 'test-client': Reason Code: 'SUCCESS'")); 104 | await().until(() -> hivemq.getLogs() 105 | .contains("Received PUBREL from client 'test-client': Reason Code: 'SUCCESS'")); 106 | await().until(() -> hivemq.getLogs().contains("Sent PUBCOMP to client 'test-client': Reason Code: 'SUCCESS'")); 107 | 108 | await().until(() -> hivemq.getLogs() 109 | .contains( 110 | "Sent PUBLISH to client 'test-client' on topic 'publish': Payload: 'payload1', QoS: '2', Retained: 'false'")); 111 | await().until(() -> hivemq.getLogs() 112 | .contains("Received PUBREC from client 'test-client': Reason Code: 'SUCCESS'")); 113 | await().until(() -> hivemq.getLogs().contains("Sent PUBREL to client 'test-client': Reason Code: 'SUCCESS'")); 114 | await().until(() -> hivemq.getLogs() 115 | .contains("Received PUBCOMP from client 'test-client': Reason Code: 'SUCCESS'")); 116 | 117 | client.publishWith() 118 | .topic("publish") 119 | .qos(MqttQos.AT_LEAST_ONCE) 120 | .payload("payload2".getBytes(StandardCharsets.UTF_8)) 121 | .contentType("text/plain") 122 | .correlationData("willCorrelationData".getBytes(StandardCharsets.UTF_8)) 123 | .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) 124 | .responseTopic("publishResponse") 125 | .retain(false) 126 | .messageExpiryInterval(10_000) 127 | .userProperties() 128 | .add("publishProperty", "publishValue") 129 | .applyUserProperties() 130 | .send(); 131 | await().until(() -> hivemq.getLogs() 132 | .contains( 133 | "Received PUBLISH from client 'test-client' for topic 'publish': Payload: 'payload2', QoS: '1', Retained: 'false'")); 134 | await().until(() -> hivemq.getLogs().contains("Sent PUBACK to client 'test-client': Reason Code: 'SUCCESS'")); 135 | await().until(() -> hivemq.getLogs() 136 | .contains( 137 | "Sent PUBLISH to client 'test-client' on topic 'publish': Payload: 'payload2', QoS: '1', Retained: 'false'")); 138 | await().until(() -> hivemq.getLogs() 139 | .contains("Received PUBACK from client 'test-client': Reason Code: 'SUCCESS'")); 140 | 141 | client.unsubscribeWith().topicFilter("#").send(); 142 | await().until(() -> hivemq.getLogs() 143 | .contains("Received UNSUBSCRIBE from client 'test-client': Topics: { [Topic: '#'] }")); 144 | await().until(() -> hivemq.getLogs() 145 | .contains("Sent UNSUBACK to client 'test-client': Unsuback Reason Codes: { [Reason Code: 'SUCCESS'] }")); 146 | 147 | client.disconnect(); 148 | await().until(() -> hivemq.getLogs() 149 | .contains("Received DISCONNECT from client 'test-client': Reason Code: 'NORMAL_DISCONNECTION'")); 150 | 151 | assertTrue(hivemq.getLogs().contains("Payload: 'payload1'")); 152 | assertTrue(hivemq.getLogs().contains("Payload: 'payload2'")); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/integrationTest/resources/fullConfig.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019-present HiveMQ GmbH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | verbose=true 17 | payload=true 18 | publish-received=true 19 | publish-send=true 20 | client-connect=true 21 | connack-send=true 22 | client-disconnect=true 23 | subscribe-received=true 24 | suback-send=true 25 | unsubscribe-received=true 26 | unsuback-send=true 27 | ping-request-received=true 28 | ping-response-send=true 29 | puback-received=true 30 | puback-send=true 31 | pubrec-received=true 32 | pubrec-send=true 33 | pubrel-received=true 34 | pubrel-send=true 35 | pubcomp-received=true 36 | pubcomp-send=true 37 | -------------------------------------------------------------------------------- /src/integrationTest/resources/fullConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 21 | true 22 | true 23 | true 24 | true 25 | true 26 | true 27 | true 28 | true 29 | true 30 | true 31 | true 32 | true 33 | true 34 | true 35 | true 36 | true 37 | true 38 | true 39 | true 40 | true 41 | true 42 | 43 | -------------------------------------------------------------------------------- /src/integrationTest/resources/fullConfigNoPayload.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019-present HiveMQ GmbH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | verbose=true 17 | payload=false 18 | publish-received=true 19 | publish-send=true 20 | client-connect=true 21 | connack-send=true 22 | client-disconnect=true 23 | subscribe-received=true 24 | suback-send=true 25 | unsubscribe-received=true 26 | unsuback-send=true 27 | ping-request-received=true 28 | ping-response-send=true 29 | puback-received=true 30 | puback-send=true 31 | pubrec-received=true 32 | pubrec-send=true 33 | pubrel-received=true 34 | pubrel-send=true 35 | pubcomp-received=true 36 | pubcomp-send=true 37 | -------------------------------------------------------------------------------- /src/integrationTest/resources/fullConfigNoPayload.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 21 | true 22 | false 23 | true 24 | true 25 | true 26 | true 27 | true 28 | true 29 | true 30 | true 31 | true 32 | true 33 | true 34 | true 35 | true 36 | true 37 | true 38 | true 39 | true 40 | true 41 | true 42 | 43 | -------------------------------------------------------------------------------- /src/integrationTest/resources/fullConfigNoPayloadNoVerbose.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019-present HiveMQ GmbH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | verbose=false 17 | payload=false 18 | publish-received=true 19 | publish-send=true 20 | client-connect=true 21 | connack-send=true 22 | client-disconnect=true 23 | subscribe-received=true 24 | suback-send=true 25 | unsubscribe-received=true 26 | unsuback-send=true 27 | ping-request-received=true 28 | ping-response-send=true 29 | puback-received=true 30 | puback-send=true 31 | pubrec-received=true 32 | pubrec-send=true 33 | pubrel-received=true 34 | pubrel-send=true 35 | pubcomp-received=true 36 | pubcomp-send=true 37 | -------------------------------------------------------------------------------- /src/integrationTest/resources/fullConfigNoPayloadNoVerbose.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 21 | false 22 | false 23 | true 24 | true 25 | true 26 | true 27 | true 28 | true 29 | true 30 | true 31 | true 32 | true 33 | true 34 | true 35 | true 36 | true 37 | true 38 | true 39 | true 40 | true 41 | true 42 | 43 | -------------------------------------------------------------------------------- /src/integrationTest/resources/fullConfigNoVerbose.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019-present HiveMQ GmbH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | verbose=false 17 | payload=true 18 | publish-received=true 19 | publish-send=true 20 | client-connect=true 21 | connack-send=true 22 | client-disconnect=true 23 | subscribe-received=true 24 | suback-send=true 25 | unsubscribe-received=true 26 | unsuback-send=true 27 | ping-request-received=true 28 | ping-response-send=true 29 | puback-received=true 30 | puback-send=true 31 | pubrec-received=true 32 | pubrec-send=true 33 | pubrel-received=true 34 | pubrel-send=true 35 | pubcomp-received=true 36 | pubcomp-send=true 37 | -------------------------------------------------------------------------------- /src/integrationTest/resources/fullConfigNoVerbose.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 21 | false 22 | true 23 | true 24 | true 25 | true 26 | true 27 | true 28 | true 29 | true 30 | true 31 | true 32 | true 33 | true 34 | true 35 | true 36 | true 37 | true 38 | true 39 | true 40 | true 41 | true 42 | 43 | -------------------------------------------------------------------------------- /src/integrationTest/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | %-30(%d %level)- %msg%n%ex 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/ExtensionConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message; 17 | 18 | import org.jetbrains.annotations.NotNull; 19 | 20 | public class ExtensionConstants { 21 | 22 | public static final @NotNull String EXTENSION_NAME = "HiveMQ MQTT Message Log Extension"; 23 | 24 | public static final @NotNull String EXTENSION_CONFIG_PROPERTIES_LOCATION = "mqttMessageLog.properties"; 25 | public static final @NotNull String EXTENSION_CONFIG_XML_LOCATION = "conf/config.xml"; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/MqttMessageLogExtensionMain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message; 17 | 18 | import com.hivemq.extension.sdk.api.ExtensionMain; 19 | import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; 20 | import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; 21 | import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; 22 | import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; 23 | import com.hivemq.extension.sdk.api.services.Services; 24 | import com.hivemq.extension.sdk.api.services.admin.LicenseEdition; 25 | import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; 26 | import com.hivemq.extensions.log.mqtt.message.config.ExtensionConfig; 27 | import com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigReader; 28 | import com.hivemq.extensions.log.mqtt.message.initializer.ClientInitializerImpl; 29 | import com.hivemq.extensions.log.mqtt.message.initializer.ClientInitializerImpl4_2; 30 | import org.jetbrains.annotations.NotNull; 31 | import org.jetbrains.annotations.VisibleForTesting; 32 | import org.slf4j.Logger; 33 | import org.slf4j.LoggerFactory; 34 | 35 | /** 36 | * @since 1.0.0 37 | */ 38 | public class MqttMessageLogExtensionMain implements ExtensionMain { 39 | 40 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(MqttMessageLogExtensionMain.class); 41 | 42 | @Override 43 | public void extensionStart( 44 | final @NotNull ExtensionStartInput extensionStartInput, 45 | final @NotNull ExtensionStartOutput extensionStartOutput) { 46 | try { 47 | extensionStartInput.getServerInformation(); 48 | } catch (final NoSuchMethodError e) { 49 | // only a version that is not supported will throw this exception 50 | extensionStartOutput.preventExtensionStartup("The HiveMQ version is not supported"); 51 | return; 52 | } 53 | 54 | try { 55 | final ExtensionConfig config = 56 | ExtensionConfigReader.read(extensionStartInput.getExtensionInformation().getExtensionHomeFolder()); 57 | 58 | if (config.allDisabled()) { 59 | extensionStartOutput.preventExtensionStartup(extensionStartInput.getExtensionInformation().getName() + 60 | " start prevented because all properties set to false"); 61 | return; 62 | } 63 | 64 | final ClientInitializer initializer = 65 | getClientInitializerForEdition(Services.adminService().getLicenseInformation().getEdition(), 66 | extensionStartInput.getServerInformation().getVersion(), 67 | config); 68 | 69 | Services.initializerRegistry().setClientInitializer(initializer); 70 | 71 | } catch (final Exception e) { 72 | extensionStartOutput.preventExtensionStartup(extensionStartInput.getExtensionInformation().getName() + 73 | " cannot be started"); 74 | LOG.error("{} could not be started. An exception was thrown!", 75 | extensionStartInput.getExtensionInformation().getName(), 76 | e); 77 | } 78 | } 79 | 80 | @Override 81 | public void extensionStop( 82 | final @NotNull ExtensionStopInput extensionStopInput, 83 | final @NotNull ExtensionStopOutput extensionStopOutput) { 84 | } 85 | 86 | @VisibleForTesting 87 | @NotNull 88 | ClientInitializer getClientInitializerForEdition( 89 | final @NotNull LicenseEdition edition, 90 | final @NotNull String version, 91 | final @NotNull ExtensionConfig config) { 92 | if (LicenseEdition.COMMUNITY.equals(edition)) { 93 | return new ClientInitializerImpl(config); 94 | } else if (version.startsWith("4.2.")) { 95 | return new ClientInitializerImpl4_2(config); 96 | } else { 97 | return new ClientInitializerImpl(config); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/config/ExtensionConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.config; 17 | 18 | /** 19 | * @since 1.2.0 20 | */ 21 | public interface ExtensionConfig { 22 | 23 | boolean isClientConnect(); 24 | 25 | boolean isClientDisconnect(); 26 | 27 | boolean isConnackSend(); 28 | 29 | boolean isPublishReceived(); 30 | 31 | boolean isPublishSend(); 32 | 33 | boolean isSubscribeReceived(); 34 | 35 | boolean isSubackSend(); 36 | 37 | boolean isUnsubscribeReceived(); 38 | 39 | boolean isUnsubackSend(); 40 | 41 | boolean isPingRequestReceived(); 42 | 43 | boolean isPingResponseSend(); 44 | 45 | boolean isPubackReceived(); 46 | 47 | boolean isPubackSend(); 48 | 49 | boolean isPubrelReceived(); 50 | 51 | boolean isPubrelSend(); 52 | 53 | boolean isPubrecReceived(); 54 | 55 | boolean isPubrecSend(); 56 | 57 | boolean isPubcompReceived(); 58 | 59 | boolean isPubcompSend(); 60 | 61 | boolean isVerbose(); 62 | 63 | boolean isPayload(); 64 | 65 | default boolean allDisabled() { 66 | return !isClientConnect() && 67 | !isClientDisconnect() && 68 | !isConnackSend() && 69 | !isPublishSend() && 70 | !isPublishReceived() && 71 | !isSubscribeReceived() && 72 | !isSubackSend() && 73 | !isUnsubscribeReceived() && 74 | !isUnsubackSend() && 75 | !isPingRequestReceived() && 76 | !isPingResponseSend() && 77 | !isPubackReceived() && 78 | !isPubackSend() && 79 | !isPubrecReceived() && 80 | !isPubrecSend() && 81 | !isPubrelReceived() && 82 | !isPubrelSend() && 83 | !isPubcompReceived() && 84 | !isPubcompSend(); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/config/ExtensionConfigProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.config; 17 | 18 | import org.jetbrains.annotations.NotNull; 19 | import org.jetbrains.annotations.VisibleForTesting; 20 | 21 | import java.util.Properties; 22 | 23 | public class ExtensionConfigProperties implements ExtensionConfig { 24 | 25 | static final @NotNull String TRUE = "true"; 26 | static final @NotNull String FALSE = "false"; 27 | static final @NotNull String VERBOSE = "verbose"; 28 | static final @NotNull String PAYLOAD = "payload"; 29 | static final @NotNull String CLIENT_CONNECT = "client-connect"; 30 | static final @NotNull String CLIENT_DISCONNECT = "client-disconnect"; 31 | static final @NotNull String CONNACK_SEND = "connack-send"; 32 | static final @NotNull String PUBLISH_RECEIVED = "publish-received"; 33 | static final @NotNull String PUBLISH_SEND = "publish-send"; 34 | static final @NotNull String SUBSCRIBE_RECEIVED = "subscribe-received"; 35 | static final @NotNull String SUBACK_SEND = "suback-send"; 36 | static final @NotNull String UNSUBSCRIBE_RECEIVED = "unsubscribe-received"; 37 | static final @NotNull String UNSUBACK_SEND = "unsuback-send"; 38 | static final @NotNull String PING_REQUEST_RECEIVED = "ping-request-received"; 39 | static final @NotNull String PING_RESPONSE_SEND = "ping-response-send"; 40 | static final @NotNull String PUBACK_RECEIVED = "puback-received"; 41 | static final @NotNull String PUBACK_SEND = "puback-send"; 42 | static final @NotNull String PUBREC_RECEIVED = "pubrec-received"; 43 | static final @NotNull String PUBREC_SEND = "pubrec-send"; 44 | static final @NotNull String PUBREL_RECEIVED = "pubrel-received"; 45 | static final @NotNull String PUBREL_SEND = "pubrel-send"; 46 | static final @NotNull String PUBCOMP_RECEIVED = "pubcomp-received"; 47 | static final @NotNull String PUBCOMP_SEND = "pubcomp-send"; 48 | 49 | private final @NotNull Properties properties; 50 | 51 | public ExtensionConfigProperties(final @NotNull Properties properties) { 52 | this.properties = properties; 53 | } 54 | 55 | public boolean isClientConnect() { 56 | return getForKey(CLIENT_CONNECT); 57 | } 58 | 59 | public boolean isClientDisconnect() { 60 | return getForKey(CLIENT_DISCONNECT); 61 | } 62 | 63 | public boolean isConnackSend() { 64 | return getForKey(CONNACK_SEND); 65 | } 66 | 67 | public boolean isPublishReceived() { 68 | return getForKey(PUBLISH_RECEIVED); 69 | } 70 | 71 | public boolean isPublishSend() { 72 | return getForKey(PUBLISH_SEND); 73 | } 74 | 75 | public boolean isSubscribeReceived() { 76 | return getForKey(SUBSCRIBE_RECEIVED); 77 | } 78 | 79 | public boolean isSubackSend() { 80 | return getForKey(SUBACK_SEND); 81 | } 82 | 83 | public boolean isUnsubscribeReceived() { 84 | return getForKey(UNSUBSCRIBE_RECEIVED); 85 | } 86 | 87 | public boolean isUnsubackSend() { 88 | return getForKey(UNSUBACK_SEND); 89 | } 90 | 91 | public boolean isPingRequestReceived() { 92 | return getForKey(PING_REQUEST_RECEIVED); 93 | } 94 | 95 | public boolean isPingResponseSend() { 96 | return getForKey(PING_RESPONSE_SEND); 97 | } 98 | 99 | public boolean isPubackReceived() { 100 | return getForKey(PUBACK_RECEIVED); 101 | } 102 | 103 | public boolean isPubackSend() { 104 | return getForKey(PUBACK_SEND); 105 | } 106 | 107 | public boolean isPubrelReceived() { 108 | return getForKey(PUBREL_RECEIVED); 109 | } 110 | 111 | public boolean isPubrelSend() { 112 | return getForKey(PUBREL_SEND); 113 | } 114 | 115 | public boolean isPubrecReceived() { 116 | return getForKey(PUBREC_RECEIVED); 117 | } 118 | 119 | public boolean isPubrecSend() { 120 | return getForKey(PUBREC_SEND); 121 | } 122 | 123 | public boolean isPubcompReceived() { 124 | return getForKey(PUBCOMP_RECEIVED); 125 | } 126 | 127 | public boolean isPubcompSend() { 128 | return getForKey(PUBCOMP_SEND); 129 | } 130 | 131 | public boolean isVerbose() { 132 | return getForKey(VERBOSE); 133 | } 134 | 135 | public boolean isPayload() { 136 | return getForKey(PAYLOAD); 137 | } 138 | 139 | private boolean getForKey(final @NotNull String key) { 140 | return properties.getProperty(key, TRUE).equalsIgnoreCase(TRUE); 141 | } 142 | 143 | @VisibleForTesting 144 | @NotNull Properties getProperties() { 145 | return properties; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/config/ExtensionConfigReader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.config; 17 | 18 | import org.jetbrains.annotations.NotNull; 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | import java.io.File; 23 | import java.io.FileInputStream; 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | import java.nio.file.Path; 27 | import java.util.Properties; 28 | 29 | import static com.hivemq.extensions.log.mqtt.message.ExtensionConstants.EXTENSION_CONFIG_PROPERTIES_LOCATION; 30 | import static com.hivemq.extensions.log.mqtt.message.ExtensionConstants.EXTENSION_CONFIG_XML_LOCATION; 31 | import static com.hivemq.extensions.log.mqtt.message.ExtensionConstants.EXTENSION_NAME; 32 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.CLIENT_CONNECT; 33 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.CLIENT_DISCONNECT; 34 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.CONNACK_SEND; 35 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.FALSE; 36 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.PAYLOAD; 37 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.PING_REQUEST_RECEIVED; 38 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.PING_RESPONSE_SEND; 39 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.PUBACK_RECEIVED; 40 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.PUBACK_SEND; 41 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.PUBCOMP_RECEIVED; 42 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.PUBCOMP_SEND; 43 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.PUBLISH_RECEIVED; 44 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.PUBLISH_SEND; 45 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.PUBREC_RECEIVED; 46 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.PUBREC_SEND; 47 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.PUBREL_RECEIVED; 48 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.PUBREL_SEND; 49 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.SUBACK_SEND; 50 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.SUBSCRIBE_RECEIVED; 51 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.TRUE; 52 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.UNSUBACK_SEND; 53 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.UNSUBSCRIBE_RECEIVED; 54 | import static com.hivemq.extensions.log.mqtt.message.config.ExtensionConfigProperties.VERBOSE; 55 | 56 | /** 57 | * @since 1.2.0 58 | */ 59 | public class ExtensionConfigReader { 60 | 61 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(ExtensionConfigReader.class); 62 | 63 | /** 64 | * Reads config.xml from /conf directory if present, otherwise reads mqttMessageLog.properties from extension home 65 | * directory. Uses the defaults if neither is present/readable. 66 | * 67 | * @param extensionHomeFolder home folder of the extension 68 | * @return user defined extension configuration or default configuration 69 | */ 70 | public static @NotNull ExtensionConfig read(final @NotNull File extensionHomeFolder) { 71 | final File configXmlFile = extensionHomeFolder.toPath().resolve(EXTENSION_CONFIG_XML_LOCATION).toFile(); 72 | 73 | if (!configXmlFile.exists()) { 74 | return readPropertiesFile(extensionHomeFolder); 75 | } 76 | 77 | return readConfigXmlFile(configXmlFile); 78 | } 79 | 80 | private static ExtensionConfig readPropertiesFile(final @NotNull File extensionHomeFolder) { 81 | final Properties properties = setDefaults(); 82 | final File propertiesFile = new File(extensionHomeFolder, EXTENSION_CONFIG_PROPERTIES_LOCATION); 83 | 84 | LOG.debug("{}: Will try to read config properties from {}", 85 | EXTENSION_NAME, 86 | EXTENSION_CONFIG_PROPERTIES_LOCATION); 87 | 88 | if (propertiesFile.exists()) { 89 | final Path extensionHomePath = extensionHomeFolder.toPath(); 90 | final Path extensionLegacyConfigPropertiesPath = 91 | extensionHomePath.resolve(EXTENSION_CONFIG_PROPERTIES_LOCATION); 92 | final Path extensionConfigXmlPath = extensionHomePath.resolve(EXTENSION_CONFIG_XML_LOCATION); 93 | LOG.warn("{}: The configuration file is using the legacy location and format '{}'. " + 94 | "Please update the configuration file to the new location and format '{}'. " + 95 | "Support for the legacy location and format will be removed in a future release.", 96 | EXTENSION_NAME, 97 | extensionLegacyConfigPropertiesPath, 98 | extensionConfigXmlPath); 99 | } 100 | 101 | if (!propertiesFile.canRead()) { 102 | LOG.info("{}: Cannot read properties file {}", EXTENSION_NAME, propertiesFile.getAbsolutePath()); 103 | } else { 104 | try (final InputStream is = new FileInputStream(propertiesFile)) { 105 | properties.load(is); 106 | } catch (final Exception e) { 107 | LOG.warn("{}: Could not load properties file, reason {}", EXTENSION_NAME, e.getMessage()); 108 | } 109 | } 110 | 111 | LOG.info("{}: Properties initialized to: {}", EXTENSION_NAME, properties); 112 | return new ExtensionConfigProperties(properties); 113 | } 114 | 115 | private static @NotNull ExtensionConfigXml readConfigXmlFile(final @NotNull File configXmlFile) { 116 | ExtensionConfigXml extensionConfigXml; 117 | 118 | LOG.debug("{}: Will try to read config properties from {}", EXTENSION_NAME, EXTENSION_CONFIG_XML_LOCATION); 119 | 120 | if (!configXmlFile.canRead()) { 121 | LOG.warn("{}: Unable to read configuration file {}, using defaults", 122 | EXTENSION_NAME, 123 | configXmlFile.getAbsolutePath()); 124 | extensionConfigXml = new ExtensionConfigXml(); 125 | } else { 126 | try { 127 | extensionConfigXml = XmlParser.unmarshalExtensionConfig(configXmlFile); 128 | } catch (final IOException e) { 129 | extensionConfigXml = new ExtensionConfigXml(); 130 | LOG.warn("{}: Could not read configuration file, reason: {}, using defaults", 131 | EXTENSION_NAME, 132 | e.getMessage()); 133 | } 134 | } 135 | 136 | LOG.info("{}: Properties initialized to: {}", EXTENSION_NAME, extensionConfigXml); 137 | return extensionConfigXml; 138 | } 139 | 140 | private static @NotNull Properties setDefaults() { 141 | // these defaults must be kept in sync with those in ExtensionConfigXml 142 | final Properties properties = new Properties(); 143 | properties.setProperty(CLIENT_CONNECT, TRUE); 144 | properties.setProperty(CONNACK_SEND, TRUE); 145 | 146 | properties.setProperty(CLIENT_DISCONNECT, TRUE); 147 | 148 | properties.setProperty(PUBLISH_RECEIVED, TRUE); 149 | properties.setProperty(PUBLISH_SEND, TRUE); 150 | 151 | properties.setProperty(SUBSCRIBE_RECEIVED, TRUE); 152 | properties.setProperty(SUBACK_SEND, TRUE); 153 | 154 | properties.setProperty(UNSUBSCRIBE_RECEIVED, TRUE); 155 | properties.setProperty(UNSUBACK_SEND, TRUE); 156 | 157 | properties.setProperty(PING_REQUEST_RECEIVED, TRUE); 158 | properties.setProperty(PING_RESPONSE_SEND, TRUE); 159 | 160 | properties.setProperty(PUBACK_RECEIVED, TRUE); 161 | properties.setProperty(PUBACK_SEND, TRUE); 162 | 163 | properties.setProperty(PUBREC_RECEIVED, TRUE); 164 | properties.setProperty(PUBREC_SEND, TRUE); 165 | 166 | properties.setProperty(PUBREL_RECEIVED, TRUE); 167 | properties.setProperty(PUBREL_SEND, TRUE); 168 | 169 | properties.setProperty(PUBCOMP_RECEIVED, TRUE); 170 | properties.setProperty(PUBCOMP_SEND, TRUE); 171 | 172 | properties.setProperty(VERBOSE, FALSE); 173 | 174 | properties.setProperty(PAYLOAD, TRUE); 175 | return properties; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/config/ExtensionConfigXml.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.config; 17 | 18 | 19 | import jakarta.xml.bind.annotation.XmlAccessType; 20 | import jakarta.xml.bind.annotation.XmlAccessorType; 21 | import jakarta.xml.bind.annotation.XmlElement; 22 | import jakarta.xml.bind.annotation.XmlRootElement; 23 | import jakarta.xml.bind.annotation.XmlType; 24 | 25 | /** 26 | * @since 1.2.0 27 | */ 28 | @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "unused"}) 29 | @XmlRootElement(name = "hivemq-mqtt-message-log-extension") 30 | @XmlType(propOrder = {}) 31 | @XmlAccessorType(XmlAccessType.NONE) 32 | public class ExtensionConfigXml implements ExtensionConfig { 33 | 34 | // these defaults must be kept in sync with those in ExtensionConfigReader 35 | @XmlElement(name = "verbose", defaultValue = "false") 36 | private boolean verbose = false; 37 | 38 | @XmlElement(name = "payload", defaultValue = "true") 39 | private boolean payload = true; 40 | 41 | @XmlElement(name = "publish-received", defaultValue = "true") 42 | private boolean publishReceived = true; 43 | 44 | @XmlElement(name = "publish-send", defaultValue = "true") 45 | private boolean publishSend = true; 46 | 47 | @XmlElement(name = "client-connect", defaultValue = "true") 48 | private boolean clientConnect = true; 49 | 50 | @XmlElement(name = "connack-send", defaultValue = "true") 51 | private boolean connackSend = true; 52 | 53 | @XmlElement(name = "client-disconnect", defaultValue = "true") 54 | private boolean clientDisconnect = true; 55 | 56 | @XmlElement(name = "subscribe-received", defaultValue = "true") 57 | private boolean subscribeReceived = true; 58 | 59 | @XmlElement(name = "suback-send", defaultValue = "true") 60 | private boolean subackSend = true; 61 | 62 | @XmlElement(name = "unsubscribe-received", defaultValue = "true") 63 | private boolean unsubscribeReceived = true; 64 | 65 | @XmlElement(name = "unsuback-send", defaultValue = "true") 66 | private boolean unsubackSend = true; 67 | 68 | @XmlElement(name = "ping-request-received", defaultValue = "true") 69 | private boolean pingRequestReceived = true; 70 | 71 | @XmlElement(name = "ping-response-send", defaultValue = "true") 72 | private boolean pingResponseSend = true; 73 | 74 | @XmlElement(name = "puback-received", defaultValue = "true") 75 | private boolean pubackReceived = true; 76 | 77 | @XmlElement(name = "puback-send", defaultValue = "true") 78 | private boolean pubackSend = true; 79 | 80 | @XmlElement(name = "pubrec-received", defaultValue = "true") 81 | private boolean pubrecReceived = true; 82 | 83 | @XmlElement(name = "pubrec-send", defaultValue = "true") 84 | private boolean pubrecSend = true; 85 | 86 | @XmlElement(name = "pubrel-received", defaultValue = "true") 87 | private boolean pubrelReceived = true; 88 | 89 | @XmlElement(name = "pubrel-send", defaultValue = "true") 90 | private boolean pubrelSend = true; 91 | 92 | @XmlElement(name = "pubcomp-received", defaultValue = "true") 93 | private boolean pubcompReceived = true; 94 | 95 | @XmlElement(name = "pubcomp-send", defaultValue = "true") 96 | private boolean pubcompSend = true; 97 | 98 | public boolean isVerbose() { 99 | return verbose; 100 | } 101 | 102 | public boolean isPayload() { 103 | return payload; 104 | } 105 | 106 | public boolean isPublishReceived() { 107 | return publishReceived; 108 | } 109 | 110 | public boolean isPublishSend() { 111 | return publishSend; 112 | } 113 | 114 | public boolean isClientConnect() { 115 | return clientConnect; 116 | } 117 | 118 | public boolean isConnackSend() { 119 | return connackSend; 120 | } 121 | 122 | public boolean isClientDisconnect() { 123 | return clientDisconnect; 124 | } 125 | 126 | public boolean isSubscribeReceived() { 127 | return subscribeReceived; 128 | } 129 | 130 | public boolean isSubackSend() { 131 | return subackSend; 132 | } 133 | 134 | public boolean isUnsubscribeReceived() { 135 | return unsubscribeReceived; 136 | } 137 | 138 | public boolean isUnsubackSend() { 139 | return unsubackSend; 140 | } 141 | 142 | public boolean isPingRequestReceived() { 143 | return pingRequestReceived; 144 | } 145 | 146 | public boolean isPingResponseSend() { 147 | return pingResponseSend; 148 | } 149 | 150 | public boolean isPubackReceived() { 151 | return pubackReceived; 152 | } 153 | 154 | public boolean isPubackSend() { 155 | return pubackSend; 156 | } 157 | 158 | public boolean isPubrecReceived() { 159 | return pubrecReceived; 160 | } 161 | 162 | public boolean isPubrecSend() { 163 | return pubrecSend; 164 | } 165 | 166 | public boolean isPubrelReceived() { 167 | return pubrelReceived; 168 | } 169 | 170 | public boolean isPubrelSend() { 171 | return pubrelSend; 172 | } 173 | 174 | public boolean isPubcompReceived() { 175 | return pubcompReceived; 176 | } 177 | 178 | public boolean isPubcompSend() { 179 | return pubcompSend; 180 | } 181 | 182 | @Override 183 | public String toString() { 184 | return "{" + 185 | "verbose=" + 186 | verbose + 187 | ", payload=" + 188 | payload + 189 | ", publishReceived=" + 190 | publishReceived + 191 | ", publishSend=" + 192 | publishSend + 193 | ", clientConnect=" + 194 | clientConnect + 195 | ", connackSend=" + 196 | connackSend + 197 | ", clientDisconnect=" + 198 | clientDisconnect + 199 | ", subscribeReceived=" + 200 | subscribeReceived + 201 | ", subackSend=" + 202 | subackSend + 203 | ", unsubscribeReceived=" + 204 | unsubscribeReceived + 205 | ", unsubackSend=" + 206 | unsubackSend + 207 | ", pingRequestReceived=" + 208 | pingRequestReceived + 209 | ", pingResponseSend=" + 210 | pingResponseSend + 211 | ", pubackReceived=" + 212 | pubackReceived + 213 | ", pubackSend=" + 214 | pubackSend + 215 | ", pubrecReceived=" + 216 | pubrecReceived + 217 | ", pubrecSend=" + 218 | pubrecSend + 219 | ", pubrelReceived=" + 220 | pubrelReceived + 221 | ", pubrelSend=" + 222 | pubrelSend + 223 | ", pubcompReceived=" + 224 | pubcompReceived + 225 | ", pubcompSend=" + 226 | pubcompSend + 227 | '}'; 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/config/XmlParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.config; 17 | 18 | import com.hivemq.extensions.log.mqtt.message.ExtensionConstants; 19 | import jakarta.xml.bind.JAXBContext; 20 | import jakarta.xml.bind.JAXBException; 21 | import jakarta.xml.bind.Unmarshaller; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | import java.io.File; 27 | import java.io.IOException; 28 | 29 | /** 30 | * @since 1.2.0 31 | */ 32 | class XmlParser { 33 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(XmlParser.class); 34 | 35 | static @NotNull ExtensionConfigXml unmarshalExtensionConfig(final @NotNull File file) throws IOException { 36 | final @NotNull JAXBContext jaxb; 37 | 38 | try { 39 | jaxb = JAXBContext.newInstance(ExtensionConfigXml.class); 40 | } catch (final JAXBException e) { 41 | LOG.error("{}: Could not initialize XML parser", ExtensionConstants.EXTENSION_NAME, e); 42 | throw new RuntimeException(e); 43 | } 44 | 45 | try { 46 | final Unmarshaller unmarshaller = jaxb.createUnmarshaller(); 47 | return (ExtensionConfigXml) unmarshaller.unmarshal(file); 48 | } catch (final JAXBException e) { 49 | throw new IOException(e); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/initializer/ClientInitializerImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.initializer; 17 | 18 | import com.hivemq.extension.sdk.api.client.ClientContext; 19 | import com.hivemq.extension.sdk.api.client.parameter.InitializerInput; 20 | import com.hivemq.extension.sdk.api.services.Services; 21 | import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; 22 | import com.hivemq.extensions.log.mqtt.message.config.ExtensionConfig; 23 | import com.hivemq.extensions.log.mqtt.message.interceptor.ConnackOutboundInterceptorImpl; 24 | import com.hivemq.extensions.log.mqtt.message.interceptor.ConnectInboundInterceptorImpl; 25 | import com.hivemq.extensions.log.mqtt.message.interceptor.DisconnectInboundInterceptorImpl; 26 | import com.hivemq.extensions.log.mqtt.message.interceptor.DisconnectOutboundInterceptorImpl; 27 | import com.hivemq.extensions.log.mqtt.message.interceptor.PingreqInboundInterceptorImpl; 28 | import com.hivemq.extensions.log.mqtt.message.interceptor.PingrespOutboundInterceptorImpl; 29 | import com.hivemq.extensions.log.mqtt.message.interceptor.PubackInboundInterceptorImpl; 30 | import com.hivemq.extensions.log.mqtt.message.interceptor.PubackOutboundInterceptorImpl; 31 | import com.hivemq.extensions.log.mqtt.message.interceptor.PubcompInboundInterceptorImpl; 32 | import com.hivemq.extensions.log.mqtt.message.interceptor.PubcompOutboundInterceptorImpl; 33 | import com.hivemq.extensions.log.mqtt.message.interceptor.PublishInboundInterceptorImpl; 34 | import com.hivemq.extensions.log.mqtt.message.interceptor.PublishOutboundInterceptorImpl; 35 | import com.hivemq.extensions.log.mqtt.message.interceptor.PubrecInboundInterceptorImpl; 36 | import com.hivemq.extensions.log.mqtt.message.interceptor.PubrecOutboundInterceptorImpl; 37 | import com.hivemq.extensions.log.mqtt.message.interceptor.PubrelInboundInterceptorImpl; 38 | import com.hivemq.extensions.log.mqtt.message.interceptor.PubrelOutboundInterceptorImpl; 39 | import com.hivemq.extensions.log.mqtt.message.interceptor.SubackOutboundInterceptorImpl; 40 | import com.hivemq.extensions.log.mqtt.message.interceptor.SubscribeInboundInterceptorImpl; 41 | import com.hivemq.extensions.log.mqtt.message.interceptor.UnsubackOutboundInterceptorImpl; 42 | import com.hivemq.extensions.log.mqtt.message.interceptor.UnsubscribeInboundInterceptorImpl; 43 | import org.jetbrains.annotations.NotNull; 44 | 45 | /** 46 | * Creates a {@link ClientInitializer} that is usable since HiveMQ 4.3 Enterprise Version or Community Version 2020.1. 47 | * 48 | * @version 1.1.0 49 | */ 50 | public class ClientInitializerImpl implements ClientInitializer { 51 | 52 | private final @NotNull ExtensionConfig config; 53 | 54 | public ClientInitializerImpl(final @NotNull ExtensionConfig config) { 55 | this.config = config; 56 | init(); 57 | } 58 | 59 | /** 60 | * Initialize any logging logic that can be done without a {@link ClientInitializer}. 61 | */ 62 | private void init() { 63 | if (config.isClientConnect()) { 64 | Services.interceptorRegistry().setConnectInboundInterceptorProvider( // 65 | ignored -> new ConnectInboundInterceptorImpl(config.isVerbose(), config.isPayload())); 66 | } 67 | 68 | if (config.isConnackSend()) { 69 | Services.interceptorRegistry().setConnackOutboundInterceptorProvider( // 70 | ignored -> new ConnackOutboundInterceptorImpl(config.isVerbose())); 71 | } 72 | } 73 | 74 | @Override 75 | public void initialize( 76 | final @NotNull InitializerInput initializerInput, final @NotNull ClientContext clientContext) { 77 | if (config.isClientDisconnect()) { 78 | clientContext.addDisconnectInboundInterceptor(new DisconnectInboundInterceptorImpl(config.isVerbose())); 79 | clientContext.addDisconnectOutboundInterceptor(new DisconnectOutboundInterceptorImpl(config.isVerbose())); 80 | } 81 | 82 | if (config.isSubscribeReceived()) { 83 | clientContext.addSubscribeInboundInterceptor(new SubscribeInboundInterceptorImpl(config.isVerbose())); 84 | } 85 | if (config.isSubackSend()) { 86 | clientContext.addSubackOutboundInterceptor(new SubackOutboundInterceptorImpl(config.isVerbose())); 87 | } 88 | 89 | if (config.isPingRequestReceived()) { 90 | clientContext.addPingReqInboundInterceptor(new PingreqInboundInterceptorImpl()); 91 | } 92 | if (config.isPingResponseSend()) { 93 | clientContext.addPingRespOutboundInterceptor(new PingrespOutboundInterceptorImpl()); 94 | } 95 | 96 | if (config.isUnsubscribeReceived()) { 97 | clientContext.addUnsubscribeInboundInterceptor(new UnsubscribeInboundInterceptorImpl(config.isVerbose())); 98 | } 99 | if (config.isUnsubackSend()) { 100 | clientContext.addUnsubackOutboundInterceptor(new UnsubackOutboundInterceptorImpl(config.isVerbose())); 101 | } 102 | 103 | if (config.isPublishReceived()) { 104 | clientContext.addPublishInboundInterceptor(new PublishInboundInterceptorImpl(config.isVerbose(), 105 | config.isPayload())); 106 | } 107 | if (config.isPublishSend()) { 108 | clientContext.addPublishOutboundInterceptor(new PublishOutboundInterceptorImpl(config.isVerbose(), 109 | config.isPayload())); 110 | } 111 | 112 | if (config.isPubackReceived()) { 113 | clientContext.addPubackInboundInterceptor(new PubackInboundInterceptorImpl(config.isVerbose())); 114 | } 115 | if (config.isPubackSend()) { 116 | clientContext.addPubackOutboundInterceptor(new PubackOutboundInterceptorImpl(config.isVerbose())); 117 | } 118 | 119 | if (config.isPubrecReceived()) { 120 | clientContext.addPubrecInboundInterceptor(new PubrecInboundInterceptorImpl(config.isVerbose())); 121 | } 122 | if (config.isPubrecSend()) { 123 | clientContext.addPubrecOutboundInterceptor(new PubrecOutboundInterceptorImpl(config.isVerbose())); 124 | } 125 | 126 | if (config.isPubrelReceived()) { 127 | clientContext.addPubrelInboundInterceptor(new PubrelInboundInterceptorImpl(config.isVerbose())); 128 | } 129 | if (config.isPubrelSend()) { 130 | clientContext.addPubrelOutboundInterceptor(new PubrelOutboundInterceptorImpl(config.isVerbose())); 131 | } 132 | 133 | if (config.isPubcompReceived()) { 134 | clientContext.addPubcompInboundInterceptor(new PubcompInboundInterceptorImpl(config.isVerbose())); 135 | } 136 | if (config.isPubcompSend()) { 137 | clientContext.addPubcompOutboundInterceptor(new PubcompOutboundInterceptorImpl(config.isVerbose())); 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/initializer/ClientInitializerImpl4_2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.initializer; 17 | 18 | import com.hivemq.extension.sdk.api.client.ClientContext; 19 | import com.hivemq.extension.sdk.api.client.parameter.InitializerInput; 20 | import com.hivemq.extension.sdk.api.services.Services; 21 | import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; 22 | import com.hivemq.extensions.log.mqtt.message.config.ExtensionConfig; 23 | import com.hivemq.extensions.log.mqtt.message.interceptor.ConnectDisconnectEventListener; 24 | import com.hivemq.extensions.log.mqtt.message.interceptor.ConnectInboundInterceptorImpl; 25 | import com.hivemq.extensions.log.mqtt.message.interceptor.PublishInboundInterceptorImpl; 26 | import com.hivemq.extensions.log.mqtt.message.interceptor.PublishOutboundInterceptorImpl; 27 | import com.hivemq.extensions.log.mqtt.message.interceptor.SubscribeInboundInterceptorImpl; 28 | import org.jetbrains.annotations.NotNull; 29 | 30 | /** 31 | * Creates a {@link ClientInitializer} that is usable for any HiveMQ 4.2 Enterprise Version. 32 | * 33 | * @version 1.1.0 34 | */ 35 | public class ClientInitializerImpl4_2 implements ClientInitializer { 36 | 37 | private final @NotNull ExtensionConfig config; 38 | 39 | public ClientInitializerImpl4_2(final @NotNull ExtensionConfig config) { 40 | this.config = config; 41 | init(); 42 | } 43 | 44 | /** 45 | * Initialize any logging logic that can be done without a {@link ClientInitializer}. 46 | */ 47 | private void init() { 48 | if (config.isClientConnect() && config.isClientDisconnect()) { 49 | Services.eventRegistry().setClientLifecycleEventListener( // 50 | input -> new ConnectDisconnectEventListener(true, config.isVerbose(), config.isPayload())); 51 | } else if (config.isClientDisconnect()) { 52 | Services.eventRegistry().setClientLifecycleEventListener( // 53 | input -> new ConnectDisconnectEventListener(false, config.isVerbose(), config.isPayload())); 54 | } else if (config.isClientConnect()) { 55 | Services.interceptorRegistry().setConnectInboundInterceptorProvider( // 56 | input -> new ConnectInboundInterceptorImpl(config.isVerbose(), config.isPayload())); 57 | } 58 | } 59 | 60 | @Override 61 | public void initialize( 62 | final @NotNull InitializerInput initializerInput, final @NotNull ClientContext clientContext) { 63 | if (config.isSubscribeReceived()) { 64 | clientContext.addSubscribeInboundInterceptor(new SubscribeInboundInterceptorImpl(config.isVerbose())); 65 | } 66 | if (config.isPublishReceived()) { 67 | clientContext.addPublishInboundInterceptor(new PublishInboundInterceptorImpl(config.isVerbose(), 68 | config.isPayload())); 69 | } 70 | if (config.isPublishSend()) { 71 | clientContext.addPublishOutboundInterceptor(new PublishOutboundInterceptorImpl(config.isVerbose(), 72 | config.isPayload())); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/ConnackOutboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.connack.ConnackOutboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.connack.parameter.ConnackOutboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.connack.parameter.ConnackOutboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class ConnackOutboundInterceptorImpl implements ConnackOutboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(ConnackOutboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public ConnackOutboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onOutboundConnack( 40 | final @NotNull ConnackOutboundInput connackOutboundInput, 41 | final @NotNull ConnackOutboundOutput connackOutboundOutput) { 42 | try { 43 | MessageLogUtil.logConnack(connackOutboundInput, verbose); 44 | } catch (final Exception e) { 45 | LOG.debug("Exception thrown at outbound connack logging: ", e); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/ConnectDisconnectEventListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.events.client.ClientLifecycleEventListener; 19 | import com.hivemq.extension.sdk.api.events.client.parameters.AuthenticationFailedInput; 20 | import com.hivemq.extension.sdk.api.events.client.parameters.AuthenticationSuccessfulInput; 21 | import com.hivemq.extension.sdk.api.events.client.parameters.ClientInitiatedDisconnectInput; 22 | import com.hivemq.extension.sdk.api.events.client.parameters.ConnectionLostInput; 23 | import com.hivemq.extension.sdk.api.events.client.parameters.ConnectionStartInput; 24 | import com.hivemq.extension.sdk.api.events.client.parameters.DisconnectEventInput; 25 | import com.hivemq.extension.sdk.api.events.client.parameters.ServerInitiatedDisconnectInput; 26 | import com.hivemq.extension.sdk.api.packets.connect.ConnectPacket; 27 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 28 | import org.jetbrains.annotations.NotNull; 29 | import org.slf4j.Logger; 30 | import org.slf4j.LoggerFactory; 31 | 32 | /** 33 | * @since 1.0.0 34 | */ 35 | public class ConnectDisconnectEventListener implements ClientLifecycleEventListener { 36 | 37 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(ConnectDisconnectEventListener.class); 38 | 39 | private final boolean logConnect; 40 | private final boolean verbose; 41 | private final boolean payload; 42 | 43 | public ConnectDisconnectEventListener(final boolean logConnect, final boolean verbose, final boolean payload) { 44 | this.logConnect = logConnect; 45 | this.verbose = verbose; 46 | this.payload = payload; 47 | } 48 | 49 | @Override 50 | public void onMqttConnectionStart(final @NotNull ConnectionStartInput connectionStartInput) { 51 | if (!logConnect) { 52 | return; 53 | } 54 | try { 55 | final ConnectPacket connectPacket = connectionStartInput.getConnectPacket(); 56 | MessageLogUtil.logConnect(connectPacket, verbose, payload); 57 | } catch (final Exception e) { 58 | LOG.debug("Exception thrown at inbound connect logging: ", e); 59 | } 60 | } 61 | 62 | @Override 63 | public void onAuthenticationSuccessful(final @NotNull AuthenticationSuccessfulInput authenticationSuccessfulInput) { 64 | //NOOP 65 | } 66 | 67 | @Override 68 | public void onDisconnect(final @NotNull DisconnectEventInput disconnectEventInput) { 69 | //NOOP 70 | } 71 | 72 | @Override 73 | public void onAuthenticationFailedDisconnect(final @NotNull AuthenticationFailedInput authenticationFailedInput) { 74 | MessageLogUtil.logDisconnect(String.format("Sent DISCONNECT to client '%s' because authentication failed.", 75 | authenticationFailedInput.getClientInformation().getClientId()), authenticationFailedInput, verbose); 76 | } 77 | 78 | @Override 79 | public void onConnectionLost(final @NotNull ConnectionLostInput connectionLostInput) { 80 | //NOOP since no mqtt message is sent. 81 | } 82 | 83 | @Override 84 | public void onClientInitiatedDisconnect(final @NotNull ClientInitiatedDisconnectInput clientInitiatedDisconnectInput) { 85 | MessageLogUtil.logDisconnect(String.format("Received DISCONNECT from client '%s':", 86 | clientInitiatedDisconnectInput.getClientInformation().getClientId()), 87 | clientInitiatedDisconnectInput, 88 | verbose); 89 | } 90 | 91 | @Override 92 | public void onServerInitiatedDisconnect(final @NotNull ServerInitiatedDisconnectInput serverInitiatedDisconnectInput) { 93 | MessageLogUtil.logDisconnect(String.format("Sent DISCONNECT to client '%s':", 94 | serverInitiatedDisconnectInput.getClientInformation().getClientId()), 95 | serverInitiatedDisconnectInput, 96 | verbose); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/ConnectInboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.connect.ConnectInboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.connect.parameter.ConnectInboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.connect.parameter.ConnectInboundOutput; 21 | import com.hivemq.extension.sdk.api.packets.connect.ConnectPacket; 22 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 23 | import org.jetbrains.annotations.NotNull; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | /** 28 | * @since 1.0.0 29 | */ 30 | public class ConnectInboundInterceptorImpl implements ConnectInboundInterceptor { 31 | 32 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(ConnectInboundInterceptorImpl.class); 33 | private final boolean verbose; 34 | private final boolean payload; 35 | 36 | public ConnectInboundInterceptorImpl(final boolean verbose, final boolean payload) { 37 | this.verbose = verbose; 38 | this.payload = payload; 39 | } 40 | 41 | @Override 42 | public void onConnect( 43 | final @NotNull ConnectInboundInput connectInboundInput, 44 | final @NotNull ConnectInboundOutput connectInboundOutput) { 45 | try { 46 | final ConnectPacket connectPacket = connectInboundInput.getConnectPacket(); 47 | MessageLogUtil.logConnect(connectPacket, verbose, payload); 48 | } catch (final Exception e) { 49 | LOG.debug("Exception thrown at inbound connect logging: ", e); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/DisconnectInboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.disconnect.DisconnectInboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.disconnect.parameter.DisconnectInboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.disconnect.parameter.DisconnectInboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class DisconnectInboundInterceptorImpl implements DisconnectInboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(DisconnectInboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public DisconnectInboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onInboundDisconnect( 40 | final @NotNull DisconnectInboundInput disconnectInboundInput, 41 | final @NotNull DisconnectInboundOutput disconnectInboundOutput) { 42 | try { 43 | final String clientId = disconnectInboundInput.getClientInformation().getClientId(); 44 | MessageLogUtil.logDisconnect(disconnectInboundInput.getDisconnectPacket(), clientId, true, verbose); 45 | } catch (final Exception e) { 46 | LOG.debug("Exception thrown at inbound disconnect logging: ", e); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/DisconnectOutboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.disconnect.DisconnectOutboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.disconnect.parameter.DisconnectOutboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.disconnect.parameter.DisconnectOutboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class DisconnectOutboundInterceptorImpl implements DisconnectOutboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(DisconnectOutboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public DisconnectOutboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onOutboundDisconnect( 40 | final @NotNull DisconnectOutboundInput disconnectOutboundInput, 41 | final @NotNull DisconnectOutboundOutput disconnectOutboundOutput) { 42 | try { 43 | final String clientId = disconnectOutboundInput.getClientInformation().getClientId(); 44 | MessageLogUtil.logDisconnect(disconnectOutboundInput.getDisconnectPacket(), clientId, false, verbose); 45 | } catch (final Exception e) { 46 | LOG.debug("Exception thrown at outbound disconnect logging: ", e); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/PingreqInboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.pingreq.PingReqInboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.pingreq.parameter.PingReqInboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.pingreq.parameter.PingReqInboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class PingreqInboundInterceptorImpl implements PingReqInboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(PingreqInboundInterceptorImpl.class); 32 | 33 | @Override 34 | public void onInboundPingReq( 35 | final @NotNull PingReqInboundInput pingReqInboundInput, 36 | final @NotNull PingReqInboundOutput pingReqInboundOutput) { 37 | try { 38 | MessageLogUtil.logPingreq(pingReqInboundInput); 39 | } catch (final Exception e) { 40 | LOG.debug("Exception thrown at inbound ping request logging: ", e); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/PingrespOutboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.pingresp.PingRespOutboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.pingresp.parameter.PingRespOutboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.pingresp.parameter.PingRespOutboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class PingrespOutboundInterceptorImpl implements PingRespOutboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(PingrespOutboundInterceptorImpl.class); 32 | 33 | @Override 34 | public void onOutboundPingResp( 35 | final @NotNull PingRespOutboundInput pingRespOutboundInput, 36 | final @NotNull PingRespOutboundOutput pingRespOutboundOutput) { 37 | try { 38 | MessageLogUtil.logPingresp(pingRespOutboundInput); 39 | } catch (final Exception e) { 40 | LOG.debug("Exception thrown at outbound ping response logging: ", e); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/PubackInboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.puback.PubackInboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.puback.parameter.PubackInboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.puback.parameter.PubackInboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class PubackInboundInterceptorImpl implements PubackInboundInterceptor { 30 | 31 | private static final @NotNull Logger log = LoggerFactory.getLogger(PubackInboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public PubackInboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onInboundPuback( 40 | final @NotNull PubackInboundInput pubackInboundInput, 41 | final @NotNull PubackInboundOutput pubackInboundOutput) { 42 | try { 43 | @NotNull final String clientId = pubackInboundInput.getClientInformation().getClientId(); 44 | MessageLogUtil.logPuback(pubackInboundInput.getPubackPacket(), clientId, true, verbose); 45 | } catch (final Exception e) { 46 | log.debug("Exception thrown at inbound puback logging: ", e); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/PubackOutboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.puback.PubackOutboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.puback.parameter.PubackOutboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.puback.parameter.PubackOutboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class PubackOutboundInterceptorImpl implements PubackOutboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(PubackOutboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public PubackOutboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onOutboundPuback( 40 | final @NotNull PubackOutboundInput pubackOutboundInput, 41 | final @NotNull PubackOutboundOutput pubackOutboundOutput) { 42 | try { 43 | final String clientId = pubackOutboundInput.getClientInformation().getClientId(); 44 | MessageLogUtil.logPuback(pubackOutboundInput.getPubackPacket(), clientId, false, verbose); 45 | } catch (final Exception e) { 46 | LOG.debug("Exception thrown at outbound puback logging: ", e); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/PubcompInboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.pubcomp.PubcompInboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.pubcomp.parameter.PubcompInboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.pubcomp.parameter.PubcompInboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class PubcompInboundInterceptorImpl implements PubcompInboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(PubcompInboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public PubcompInboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onInboundPubcomp( 40 | final @NotNull PubcompInboundInput pubcompInboundInput, 41 | final @NotNull PubcompInboundOutput pubcompInboundOutput) { 42 | try { 43 | final String clientId = pubcompInboundInput.getClientInformation().getClientId(); 44 | MessageLogUtil.logPubcomp(pubcompInboundInput.getPubcompPacket(), clientId, true, verbose); 45 | } catch (final Exception e) { 46 | LOG.debug("Exception thrown at inbound pubcomp logging: ", e); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/PubcompOutboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.pubcomp.PubcompOutboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.pubcomp.parameter.PubcompOutboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.pubcomp.parameter.PubcompOutboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class PubcompOutboundInterceptorImpl implements PubcompOutboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(PubcompOutboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public PubcompOutboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onOutboundPubcomp( 40 | final @NotNull PubcompOutboundInput pubcompOutboundInput, 41 | final @NotNull PubcompOutboundOutput pubcompOutboundOutput) { 42 | try { 43 | final String clientId = pubcompOutboundInput.getClientInformation().getClientId(); 44 | MessageLogUtil.logPubcomp(pubcompOutboundInput.getPubcompPacket(), clientId, false, verbose); 45 | } catch (final Exception e) { 46 | LOG.debug("Exception thrown at outbound pubcomp logging: ", e); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/PublishInboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.publish.parameter.PublishInboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.publish.parameter.PublishInboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.0.0 28 | */ 29 | public class PublishInboundInterceptorImpl implements PublishInboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(PublishInboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | private final boolean payload; 34 | 35 | public PublishInboundInterceptorImpl(final boolean verbose, final boolean payload) { 36 | this.verbose = verbose; 37 | this.payload = payload; 38 | } 39 | 40 | @Override 41 | public void onInboundPublish( 42 | final @NotNull PublishInboundInput publishInboundInput, 43 | final @NotNull PublishInboundOutput publishInboundOutput) { 44 | try { 45 | final String clientID = publishInboundInput.getClientInformation().getClientId(); 46 | MessageLogUtil.logPublish(String.format("Received PUBLISH from client '%s' for topic", clientID), 47 | publishInboundInput.getPublishPacket(), 48 | verbose, 49 | payload); 50 | } catch (final Exception e) { 51 | LOG.debug("Exception thrown at inbound publish logging: ", e); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/PublishOutboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.publish.PublishOutboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.publish.parameter.PublishOutboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.publish.parameter.PublishOutboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.0.0 28 | */ 29 | public class PublishOutboundInterceptorImpl implements PublishOutboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(PublishOutboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | private final boolean payload; 34 | 35 | public PublishOutboundInterceptorImpl(final boolean verbose, final boolean payload) { 36 | this.verbose = verbose; 37 | this.payload = payload; 38 | } 39 | 40 | @Override 41 | public void onOutboundPublish( 42 | final @NotNull PublishOutboundInput publishOutboundInput, 43 | final @NotNull PublishOutboundOutput publishOutboundOutput) { 44 | try { 45 | final String clientID = publishOutboundInput.getClientInformation().getClientId(); 46 | MessageLogUtil.logPublish(String.format("Sent PUBLISH to client '%s' on topic", clientID), 47 | publishOutboundInput.getPublishPacket(), 48 | verbose, 49 | payload); 50 | } catch (final Exception e) { 51 | LOG.debug("Exception thrown at outbound publish logging: ", e); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/PubrecInboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.pubrec.PubrecInboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.pubrec.parameter.PubrecInboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.pubrec.parameter.PubrecInboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class PubrecInboundInterceptorImpl implements PubrecInboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(PubrecInboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public PubrecInboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onInboundPubrec( 40 | final @NotNull PubrecInboundInput pubrecInboundInput, 41 | final @NotNull PubrecInboundOutput pubrecInboundOutput) { 42 | try { 43 | final String clientId = pubrecInboundInput.getClientInformation().getClientId(); 44 | MessageLogUtil.logPubrec(pubrecInboundInput.getPubrecPacket(), clientId, true, verbose); 45 | } catch (final Exception e) { 46 | LOG.debug("Exception thrown at inbound pubrec logging: ", e); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/PubrecOutboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.pubrec.PubrecOutboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.pubrec.parameter.PubrecOutboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.pubrec.parameter.PubrecOutboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class PubrecOutboundInterceptorImpl implements PubrecOutboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(PubrecOutboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public PubrecOutboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onOutboundPubrec( 40 | final @NotNull PubrecOutboundInput pubrecOutboundInput, 41 | final @NotNull PubrecOutboundOutput pubrecOutboundOutput) { 42 | try { 43 | final String clientId = pubrecOutboundInput.getClientInformation().getClientId(); 44 | MessageLogUtil.logPubrec(pubrecOutboundInput.getPubrecPacket(), clientId, false, verbose); 45 | } catch (final Exception e) { 46 | LOG.debug("Exception thrown at outbound pubrec logging: ", e); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/PubrelInboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.pubrel.PubrelInboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.pubrel.parameter.PubrelInboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.pubrel.parameter.PubrelInboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class PubrelInboundInterceptorImpl implements PubrelInboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(PubrelInboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public PubrelInboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onInboundPubrel( 40 | final @NotNull PubrelInboundInput pubrelInboundInput, 41 | final @NotNull PubrelInboundOutput pubrelInboundOutput) { 42 | try { 43 | final String clientId = pubrelInboundInput.getClientInformation().getClientId(); 44 | MessageLogUtil.logPubrel(pubrelInboundInput.getPubrelPacket(), clientId, true, verbose); 45 | } catch (final Exception e) { 46 | LOG.debug("Exception thrown at inbound pubrel logging: ", e); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/PubrelOutboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.pubrel.PubrelOutboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.pubrel.parameter.PubrelOutboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.pubrel.parameter.PubrelOutboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class PubrelOutboundInterceptorImpl implements PubrelOutboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(PubrelOutboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public PubrelOutboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onOutboundPubrel( 40 | final @NotNull PubrelOutboundInput pubrelOutboundInput, 41 | final @NotNull PubrelOutboundOutput pubrelOutboundOutput) { 42 | try { 43 | final String clientId = pubrelOutboundInput.getClientInformation().getClientId(); 44 | MessageLogUtil.logPubrel(pubrelOutboundInput.getPubrelPacket(), clientId, false, verbose); 45 | } catch (final Exception e) { 46 | LOG.debug("Exception thrown at outbound pubrel logging: ", e); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/SubackOutboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.suback.SubackOutboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.suback.parameter.SubackOutboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.suback.parameter.SubackOutboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class SubackOutboundInterceptorImpl implements SubackOutboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(SubackOutboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public SubackOutboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onOutboundSuback( 40 | final @NotNull SubackOutboundInput subackOutboundInput, 41 | final @NotNull SubackOutboundOutput subackOutboundOutput) { 42 | try { 43 | MessageLogUtil.logSuback(subackOutboundInput, verbose); 44 | } catch (final Exception e) { 45 | LOG.debug("Exception thrown at outbound suback logging: ", e); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/SubscribeInboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.subscribe.SubscribeInboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.subscribe.parameter.SubscribeInboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.subscribe.parameter.SubscribeInboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.0.0 28 | */ 29 | public class SubscribeInboundInterceptorImpl implements SubscribeInboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(SubscribeInboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public SubscribeInboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onInboundSubscribe( 40 | final @NotNull SubscribeInboundInput subscribeInboundInput, 41 | final @NotNull SubscribeInboundOutput subscribeInboundOutput) { 42 | try { 43 | MessageLogUtil.logSubscribe(subscribeInboundInput, verbose); 44 | } catch (final Exception e) { 45 | LOG.debug("Exception thrown at inbound subscribe logging: ", e); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/UnsubackOutboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.unsuback.UnsubackOutboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.unsuback.parameter.UnsubackOutboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.unsuback.parameter.UnsubackOutboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class UnsubackOutboundInterceptorImpl implements UnsubackOutboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(UnsubackOutboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public UnsubackOutboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onOutboundUnsuback( 40 | final @NotNull UnsubackOutboundInput unsubackOutboundInput, 41 | final @NotNull UnsubackOutboundOutput unsubackOutboundOutput) { 42 | try { 43 | MessageLogUtil.logUnsuback(unsubackOutboundInput, verbose); 44 | } catch (final Exception e) { 45 | LOG.debug("Exception thrown at outbound unsuback logging: ", e); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/hivemq/extensions/log/mqtt/message/interceptor/UnsubscribeInboundInterceptorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.interceptor; 17 | 18 | import com.hivemq.extension.sdk.api.interceptor.unsubscribe.UnsubscribeInboundInterceptor; 19 | import com.hivemq.extension.sdk.api.interceptor.unsubscribe.parameter.UnsubscribeInboundInput; 20 | import com.hivemq.extension.sdk.api.interceptor.unsubscribe.parameter.UnsubscribeInboundOutput; 21 | import com.hivemq.extensions.log.mqtt.message.util.MessageLogUtil; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @since 1.1.0 28 | */ 29 | public class UnsubscribeInboundInterceptorImpl implements UnsubscribeInboundInterceptor { 30 | 31 | private static final @NotNull Logger LOG = LoggerFactory.getLogger(UnsubscribeInboundInterceptorImpl.class); 32 | private final boolean verbose; 33 | 34 | public UnsubscribeInboundInterceptorImpl(final boolean verbose) { 35 | this.verbose = verbose; 36 | } 37 | 38 | @Override 39 | public void onInboundUnsubscribe( 40 | final @NotNull UnsubscribeInboundInput unsubscribeInboundInput, 41 | final @NotNull UnsubscribeInboundOutput unsubscribeInboundOutput) { 42 | try { 43 | MessageLogUtil.logUnsubscribe(unsubscribeInboundInput, verbose); 44 | } catch (final Exception e) { 45 | LOG.debug("Exception thrown at inbound unsubscribe logging: ", e); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/resources/config.xsd: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/test/java/com/hivemq/extensions/log/mqtt/message/MqttMessageLogExtensionMainTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message; 17 | 18 | import com.hivemq.extension.sdk.api.client.parameter.ServerInformation; 19 | import com.hivemq.extension.sdk.api.parameter.ExtensionInformation; 20 | import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; 21 | import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; 22 | import com.hivemq.extension.sdk.api.services.admin.LicenseEdition; 23 | import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; 24 | import com.hivemq.extensions.log.mqtt.message.initializer.ClientInitializerImpl; 25 | import com.hivemq.extensions.log.mqtt.message.initializer.ClientInitializerImpl4_2; 26 | import org.jetbrains.annotations.NotNull; 27 | import org.junit.jupiter.api.BeforeEach; 28 | import org.junit.jupiter.api.Test; 29 | 30 | import java.io.File; 31 | 32 | import static org.junit.jupiter.api.Assertions.assertInstanceOf; 33 | import static org.mockito.Mockito.mock; 34 | import static org.mockito.Mockito.verify; 35 | import static org.mockito.Mockito.when; 36 | 37 | /** 38 | * @since 1.0.0 39 | */ 40 | class MqttMessageLogExtensionMainTest { 41 | 42 | private @NotNull ExtensionStartInput extensionStartInput; 43 | private @NotNull ExtensionStartOutput extensionStartOutput; 44 | private @NotNull MqttMessageLogExtensionMain extensionMain; 45 | 46 | @BeforeEach 47 | void setUp() { 48 | extensionStartInput = mock(ExtensionStartInput.class); 49 | extensionStartOutput = mock(ExtensionStartOutput.class); 50 | extensionMain = new MqttMessageLogExtensionMain(); 51 | } 52 | 53 | @Test 54 | void test_extension_start_prevented_no_access_to_static_components() { 55 | final ExtensionInformation information = mock(ExtensionInformation.class); 56 | final ServerInformation serverInformation = mock(ServerInformation.class); 57 | 58 | when(extensionStartInput.getExtensionInformation()).thenReturn(information); 59 | when(extensionStartInput.getServerInformation()).thenReturn(serverInformation); 60 | when(serverInformation.getVersion()).thenReturn("4"); 61 | when(information.getExtensionHomeFolder()).thenReturn(new File("some/not/existing/folder")); 62 | when(information.getName()).thenReturn("My Extension"); 63 | 64 | extensionMain.extensionStart(extensionStartInput, extensionStartOutput); 65 | verify(extensionStartOutput).preventExtensionStartup("My Extension cannot be started"); 66 | 67 | } 68 | 69 | @Test 70 | void test_extension_start_prevented_because_of_old_version() { 71 | when(extensionStartInput.getServerInformation()).thenThrow(NoSuchMethodError.class); 72 | 73 | extensionMain.extensionStart(extensionStartInput, extensionStartOutput); 74 | verify(extensionStartOutput).preventExtensionStartup("The HiveMQ version is not supported"); 75 | } 76 | 77 | @Test 78 | void getClientInitializerForEdition_4_2_0_oldImplReturned() { 79 | final ClientInitializer clientInitializerForEdition = 80 | extensionMain.getClientInitializerForEdition(LicenseEdition.ENTERPRISE, "4.2.0", mock()); 81 | assertInstanceOf(ClientInitializerImpl4_2.class, clientInitializerForEdition); 82 | } 83 | 84 | @Test 85 | void getClientInitializerForEdition_4_3_0_newImplReturned() { 86 | final ClientInitializer clientInitializerForEdition = 87 | extensionMain.getClientInitializerForEdition(LicenseEdition.ENTERPRISE, "4.3.0", mock()); 88 | assertInstanceOf(ClientInitializerImpl.class, clientInitializerForEdition); 89 | } 90 | 91 | @Test 92 | void getClientInitializerForEdition_4_20_0_newImplReturned() { 93 | final ClientInitializer clientInitializerForEdition = 94 | extensionMain.getClientInitializerForEdition(LicenseEdition.ENTERPRISE, "4.20.0", mock()); 95 | assertInstanceOf(ClientInitializerImpl.class, clientInitializerForEdition); 96 | } 97 | 98 | @Test 99 | void getClientInitializerForEdition_COMMUNITY_newImplReturned() { 100 | final ClientInitializer clientInitializerForEdition = 101 | extensionMain.getClientInitializerForEdition(LicenseEdition.COMMUNITY, "2024.1", mock()); 102 | assertInstanceOf(ClientInitializerImpl.class, clientInitializerForEdition); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/test/java/com/hivemq/extensions/log/mqtt/message/config/ExtensionConfigReaderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.config; 17 | 18 | import org.jetbrains.annotations.NotNull; 19 | import org.junit.jupiter.api.Test; 20 | import org.junit.jupiter.api.io.TempDir; 21 | 22 | import java.io.File; 23 | import java.nio.file.Path; 24 | import java.util.List; 25 | import java.util.Objects; 26 | import java.util.Properties; 27 | 28 | import static org.junit.jupiter.api.Assertions.assertEquals; 29 | import static org.junit.jupiter.api.Assertions.assertFalse; 30 | import static org.junit.jupiter.api.Assertions.assertInstanceOf; 31 | import static org.junit.jupiter.api.Assertions.assertTrue; 32 | 33 | /** 34 | * @since 1.0.0 35 | */ 36 | class ExtensionConfigReaderTest { 37 | 38 | private final int totalAvailableFlags = 21; 39 | 40 | private final @NotNull List defaultProperties = List.of(ExtensionConfigProperties.CLIENT_CONNECT, 41 | ExtensionConfigProperties.CONNACK_SEND, 42 | ExtensionConfigProperties.CLIENT_DISCONNECT, 43 | ExtensionConfigProperties.PUBLISH_RECEIVED, 44 | ExtensionConfigProperties.PUBLISH_SEND, 45 | ExtensionConfigProperties.SUBSCRIBE_RECEIVED, 46 | ExtensionConfigProperties.SUBACK_SEND, 47 | ExtensionConfigProperties.UNSUBSCRIBE_RECEIVED, 48 | ExtensionConfigProperties.UNSUBACK_SEND, 49 | ExtensionConfigProperties.PING_REQUEST_RECEIVED, 50 | ExtensionConfigProperties.PING_RESPONSE_SEND, 51 | ExtensionConfigProperties.PUBACK_RECEIVED, 52 | ExtensionConfigProperties.PUBACK_SEND, 53 | ExtensionConfigProperties.PUBREC_RECEIVED, 54 | ExtensionConfigProperties.PUBREC_SEND, 55 | ExtensionConfigProperties.PUBREL_RECEIVED, 56 | ExtensionConfigProperties.PUBREL_SEND, 57 | ExtensionConfigProperties.PUBCOMP_RECEIVED, 58 | ExtensionConfigProperties.PUBCOMP_SEND, 59 | ExtensionConfigProperties.VERBOSE, 60 | ExtensionConfigProperties.PAYLOAD); 61 | 62 | @Test 63 | void defaultPropertiesWhenNoPropertyFileInConfigFolder(@TempDir final @NotNull Path tempDir) { 64 | final ExtensionConfig extensionConfig = ExtensionConfigReader.read(tempDir.toFile()); 65 | assertInstanceOf(ExtensionConfigProperties.class, extensionConfig); 66 | 67 | final ExtensionConfigProperties extensionConfigProperties = ((ExtensionConfigProperties) extensionConfig); 68 | final Properties properties = extensionConfigProperties.getProperties(); 69 | 70 | assertEquals(properties.size(), totalAvailableFlags); 71 | assertTrue(properties.stringPropertyNames().containsAll(defaultProperties)); 72 | assertTrue(defaultProperties.containsAll(properties.stringPropertyNames())); 73 | 74 | assertTrue(extensionConfigProperties.isClientConnect()); 75 | assertTrue(extensionConfigProperties.isClientDisconnect()); 76 | assertTrue(extensionConfigProperties.isConnackSend()); 77 | assertTrue(extensionConfigProperties.isPublishReceived()); 78 | assertTrue(extensionConfigProperties.isPublishSend()); 79 | assertTrue(extensionConfigProperties.isSubscribeReceived()); 80 | assertTrue(extensionConfigProperties.isSubackSend()); 81 | assertTrue(extensionConfigProperties.isUnsubscribeReceived()); 82 | assertTrue(extensionConfigProperties.isUnsubackSend()); 83 | assertTrue(extensionConfigProperties.isPingRequestReceived()); 84 | assertTrue(extensionConfigProperties.isPingResponseSend()); 85 | assertTrue(extensionConfigProperties.isPubackReceived()); 86 | assertTrue(extensionConfigProperties.isPubackSend()); 87 | assertTrue(extensionConfigProperties.isPubrelReceived()); 88 | assertTrue(extensionConfigProperties.isPubrelSend()); 89 | assertTrue(extensionConfigProperties.isPubrecReceived()); 90 | assertTrue(extensionConfigProperties.isPubrecSend()); 91 | assertTrue(extensionConfigProperties.isPubcompReceived()); 92 | assertTrue(extensionConfigProperties.isPubcompSend()); 93 | assertFalse(extensionConfigProperties.isVerbose()); 94 | assertTrue(extensionConfigProperties.isPayload()); 95 | } 96 | 97 | @Test 98 | void nonEmptyPropertiesWhenPropertyFileInConfigFolder() { 99 | final String path = Objects.requireNonNull(getClass().getResource("/test-conf")).getPath(); 100 | final ExtensionConfig extensionConfig = ExtensionConfigReader.read(new File(path)); 101 | assertInstanceOf(ExtensionConfigProperties.class, extensionConfig); 102 | 103 | final ExtensionConfigProperties extensionConfigProperties = ((ExtensionConfigProperties) extensionConfig); 104 | final Properties properties = extensionConfigProperties.getProperties(); 105 | 106 | assertEquals(properties.size(), totalAvailableFlags); 107 | assertTrue(properties.stringPropertyNames().containsAll(defaultProperties)); 108 | assertTrue(defaultProperties.containsAll(properties.stringPropertyNames())); 109 | 110 | assertFalse(extensionConfigProperties.isVerbose()); 111 | assertTrue(extensionConfigProperties.isPayload()); 112 | assertFalse(extensionConfigProperties.isPublishReceived()); 113 | assertFalse(extensionConfigProperties.isPublishSend()); 114 | } 115 | 116 | @Test 117 | void nonEmptyPropertiesWhenConfigFileInConfFolder() { 118 | final String path = Objects.requireNonNull(getClass().getResource("/test-xml-conf")).getPath(); 119 | final ExtensionConfig extensionConfig = ExtensionConfigReader.read(new File(path)); 120 | assertInstanceOf(ExtensionConfigXml.class, extensionConfig); 121 | 122 | final ExtensionConfigXml extensionConfigXml = (ExtensionConfigXml) extensionConfig; 123 | 124 | assertFalse(extensionConfigXml.isVerbose()); 125 | assertTrue(extensionConfigXml.isPayload()); 126 | assertFalse(extensionConfigXml.isPublishReceived()); 127 | assertFalse(extensionConfigXml.isPublishSend()); 128 | } 129 | 130 | @Test 131 | void defaultPropertiesWhenInvalidConfigFileInConfFolder() { 132 | final String path = Objects.requireNonNull(getClass().getResource("/test-invalid-xml-conf")).getPath(); 133 | final ExtensionConfig extensionConfig = ExtensionConfigReader.read(new File(path)); 134 | assertInstanceOf(ExtensionConfigXml.class, extensionConfig); 135 | 136 | final ExtensionConfigXml extensionConfigXml = (ExtensionConfigXml) extensionConfig; 137 | 138 | assertTrue(extensionConfigXml.isClientConnect()); 139 | assertTrue(extensionConfigXml.isClientDisconnect()); 140 | assertTrue(extensionConfigXml.isConnackSend()); 141 | assertTrue(extensionConfigXml.isPublishReceived()); 142 | assertTrue(extensionConfigXml.isPublishSend()); 143 | assertTrue(extensionConfigXml.isSubscribeReceived()); 144 | assertTrue(extensionConfigXml.isSubackSend()); 145 | assertTrue(extensionConfigXml.isUnsubscribeReceived()); 146 | assertTrue(extensionConfigXml.isUnsubackSend()); 147 | assertTrue(extensionConfigXml.isPingRequestReceived()); 148 | assertTrue(extensionConfigXml.isPingResponseSend()); 149 | assertTrue(extensionConfigXml.isPubackReceived()); 150 | assertTrue(extensionConfigXml.isPubackSend()); 151 | assertTrue(extensionConfigXml.isPubrelReceived()); 152 | assertTrue(extensionConfigXml.isPubrelSend()); 153 | assertTrue(extensionConfigXml.isPubrecReceived()); 154 | assertTrue(extensionConfigXml.isPubrecSend()); 155 | assertTrue(extensionConfigXml.isPubcompReceived()); 156 | assertTrue(extensionConfigXml.isPubcompSend()); 157 | assertFalse(extensionConfigXml.isVerbose()); 158 | assertTrue(extensionConfigXml.isPayload()); 159 | } 160 | 161 | } 162 | -------------------------------------------------------------------------------- /src/test/java/com/hivemq/extensions/log/mqtt/message/util/LogbackTestAppender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-present HiveMQ GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hivemq.extensions.log.mqtt.message.util; 17 | 18 | import ch.qos.logback.classic.Level; 19 | import ch.qos.logback.classic.Logger; 20 | import ch.qos.logback.classic.spi.ILoggingEvent; 21 | import ch.qos.logback.core.AppenderBase; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.junit.jupiter.api.extension.AfterEachCallback; 24 | import org.junit.jupiter.api.extension.BeforeEachCallback; 25 | import org.junit.jupiter.api.extension.ExtensionContext; 26 | 27 | import java.util.LinkedList; 28 | import java.util.List; 29 | 30 | public class LogbackTestAppender extends AppenderBase implements BeforeEachCallback, AfterEachCallback { 31 | 32 | public static @NotNull LogbackTestAppender createFor(final @NotNull org.slf4j.Logger logger) { 33 | return new LogbackTestAppender((Logger) logger); 34 | } 35 | 36 | private final @NotNull Logger logger; 37 | private final @NotNull Level initialLevel; 38 | private final @NotNull List events = new LinkedList<>(); 39 | 40 | private LogbackTestAppender(final @NotNull Logger logger) { 41 | this.logger = logger; 42 | initialLevel = logger.getLevel(); 43 | } 44 | 45 | public void attach() { 46 | logger.setLevel(Level.ALL); 47 | logger.addAppender(this); 48 | start(); 49 | } 50 | 51 | public void detach() { 52 | logger.setLevel(initialLevel); 53 | logger.detachAppender(this); 54 | stop(); 55 | } 56 | 57 | @Override 58 | public void beforeEach(final @NotNull ExtensionContext ignored) { 59 | attach(); 60 | } 61 | 62 | @Override 63 | public void afterEach(final @NotNull ExtensionContext ignored) { 64 | detach(); 65 | } 66 | 67 | @Override 68 | protected void append(final @NotNull ILoggingEvent e) { 69 | events.add(e); 70 | } 71 | 72 | public @NotNull List getEvents() { 73 | return events; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/resources/test-conf/mqttMessageLog.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019-present HiveMQ GmbH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # Example properties file that will prevent the logging of 17 | # both incomming and outgoing messages, but all other 18 | # events, such as connection and subscription events, will 19 | # be logged. 20 | publish-received=false 21 | publish-send=false 22 | -------------------------------------------------------------------------------- /src/test/resources/test-invalid-xml-conf/conf/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | false 21 | false 22 | 23 | -------------------------------------------------------------------------------- /src/test/resources/test-xml-conf/conf/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 21 | false 22 | false 23 | 24 | --------------------------------------------------------------------------------