Skip to content

Commit

Permalink
[#3520] specific metrics for unknown messages
Browse files Browse the repository at this point in the history
Signed-off-by: Bob Claerhout <[email protected]>
  • Loading branch information
BobClaerhout committed Jul 25, 2023
1 parent 4a8911a commit ff18da6
Show file tree
Hide file tree
Showing 27 changed files with 528 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.eclipse.hono.util.CommandConstants;
import org.eclipse.hono.util.Constants;
import org.eclipse.hono.util.MessageHelper;
import org.eclipse.hono.util.QoS;
import org.eclipse.hono.util.RegistrationAssertion;
import org.eclipse.hono.util.Strings;
import org.eclipse.hono.util.TenantObject;
Expand Down Expand Up @@ -85,7 +86,7 @@ public abstract class AbstractVertxBasedHttpProtocolAdapter<T extends HttpProtoc

private static final String KEY_MATCH_ALL_ROUTE_APPLIED = "matchAllRouteApplied";

private HttpAdapterMetrics metrics = HttpAdapterMetrics.NOOP;
protected HttpAdapterMetrics metrics = HttpAdapterMetrics.NOOP;
private HttpServer server;
private HttpServer insecureServer;

Expand Down Expand Up @@ -203,7 +204,15 @@ public final void doStart(final Promise<Void> startPromise) {
.onComplete(startPromise);
}

private Sample getMicrometerSample(final RoutingContext ctx) {
/**
* Gets the timer used to track the processing of a telemetry message.
*
* @param ctx The routing context to extract the sample from.
* @return The sample or {@code null} if the context does not
* contain a sample.
* @throws NullPointerException if ctx is {@code null}.
*/
protected Sample getMicrometerSample(final RoutingContext ctx) {
return ctx.get(KEY_MICROMETER_SAMPLE);
}

Expand Down Expand Up @@ -1295,9 +1304,16 @@ public final void uploadCommandResponseMessage(
});
}

private static MetricsTags.QoS getQoSLevel(
final EndpointType endpoint,
final org.eclipse.hono.util.QoS requestedQos) {
/**
* Get the QoS based on the endpoint and the requested QoS.
*
* @param endpoint The endpoint the message was sent to.
* @param requestedQos The QoS requested by the sender.
* @return The resulting QoS.
*/
protected static MetricsTags.QoS getQoSLevel(
final EndpointType endpoint,
final QoS requestedQos) {

if (endpoint == EndpointType.EVENT) {
return MetricsTags.QoS.AT_LEAST_ONCE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,19 @@ void handleProviderRoute(final HttpContext ctx, final LoraProvider provider) {
currentSpan.finish();
// discard the message but return 202 to not cause errors on the LoRa provider side
handle202(ctx.getRoutingContext());

final Future<TenantObject> tenantTracker = getTenantConfiguration(gatewayDevice.getTenantId(), currentSpan.context());
final MetricsTags.EndpointType endpoint = MetricsTags.EndpointType.fromString(ctx.getRequestedResource().getEndpoint());
final MetricsTags.QoS qos = getQoSLevel(endpoint, ctx.getRequestedQos());
metrics.reportTelemetry(
endpoint,
gatewayDevice.getTenantId(),
tenantTracker.result(),
MetricsTags.ProcessingOutcome.UNKNOWN,
qos,
ctx.getRoutingContext().body().buffer().length(),
ctx.getTtdStatus(),
getMicrometerSample(ctx.getRoutingContext()));
}
} catch (final LoraProviderMalformedPayloadException e) {
LOG.debug("error processing request from provider [name: {}]", provider.getProviderName(), e);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* Copyright (c) 2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/


package org.eclipse.hono.adapter.lora;

import io.vertx.core.buffer.Buffer;


/**
* A Lora message that contains unknown data sent from an end-device to a Network Server.
*
*/
public class UnknownLoraMessage implements LoraMessage {

/**
* {@inheritDoc}
*/
@Override
public final byte[] getDevEUI() {
return new byte[0];
}

/**
* {@inheritDoc}
*/
@Override
public final String getDevEUIAsString() {
return "";
}

/**
* {@inheritDoc}
*/
@Override
public final LoraMessageType getType() {
return LoraMessageType.UNKNOWN;
}

/**
* {@inheritDoc}
*/
@Override
public final Buffer getPayload() {
return Buffer.buffer();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.eclipse.hono.adapter.lora.LoraMessage;
import org.eclipse.hono.adapter.lora.LoraMessageType;
import org.eclipse.hono.adapter.lora.LoraMetaData;
import org.eclipse.hono.adapter.lora.UnknownLoraMessage;
import org.eclipse.hono.adapter.lora.UplinkLoraMessage;
import org.eclipse.hono.util.CommandEndpoint;
import org.eclipse.hono.util.Strings;
Expand Down Expand Up @@ -51,7 +52,7 @@ public LoraMessage getMessage(final RoutingContext ctx) {
case UPLINK:
return createUplinkMessage(ctx.request(), message);
default:
throw new LoraProviderMalformedPayloadException(String.format("unsupported message type [%s]", type));
return createUnknownMessage(ctx.request(), message);
}
} catch (final RuntimeException e) {
// catch generic exception in order to also cover any (runtime) exceptions
Expand Down Expand Up @@ -184,4 +185,26 @@ protected UplinkLoraMessage createUplinkMessage(final HttpServerRequest request,
message.setAdditionalData(getAdditionalData(requestBody));
return message;
}

/**
* Creates an object representation of a Lora unknown message.
* <p>
* This method uses the {@link #getDevEui(JsonObject)}
* method to extract relevant information from the request body to add
* to the returned message.
*
* @param request The request sent by the provider's Network Server.
* @param requestBody The JSON object contained in the request's body.
* @return The message.
* @throws RuntimeException if the message cannot be parsed.
*/
protected UnknownLoraMessage createUnknownMessage(final HttpServerRequest request, final JsonObject requestBody) {

Objects.requireNonNull(requestBody);

final UnknownLoraMessage message = new UnknownLoraMessage();
return message;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ public Set<String> pathPrefixes() {
*/
@Override
public LoraMessageType getMessageType(final JsonObject loraMessage) {
return LoraMessageType.UPLINK;
if (loraMessage.containsKey(FIELD_KERLINK_PAYLOAD)) {
return LoraMessageType.UPLINK;
}
return LoraMessageType.UNKNOWN;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import java.util.Base64;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

import javax.enterprise.context.ApplicationScoped;
Expand Down Expand Up @@ -57,7 +58,12 @@ public Set<String> pathPrefixes() {
*/
@Override
public LoraMessageType getMessageType(final JsonObject loraMessage) {
return LoraMessageType.UPLINK;
final Optional<Object> payload = LoraUtils.getChildObject(loraMessage, FIELD_UPLINK_USER_DATA, JsonObject.class)
.map(userData -> userData.getValue(FIELD_UPLINK_PAYLOAD));
if (payload.isPresent()) {
return LoraMessageType.UPLINK;
}
return LoraMessageType.UNKNOWN;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ protected Buffer getPayload(final JsonObject loraMessage) {
protected LoraMessageType getMessageType(final JsonObject loraMessage) {

Objects.requireNonNull(loraMessage);
return LoraMessageType.UPLINK;
if (loraMessage.containsKey(FIELD_ORBIWISE_PAYLOAD)) {
return LoraMessageType.UPLINK;
}
return LoraMessageType.UNKNOWN;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ public Set<String> pathPrefixes() {
*/
@Override
protected LoraMessageType getMessageType(final JsonObject loraMessage) {
return LoraMessageType.UPLINK;

if (loraMessage.containsKey(FIELD_PROXIMUS_PAYLOAD)) {
return LoraMessageType.UPLINK;
}
return LoraMessageType.UNKNOWN;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ public Set<String> pathPrefixes() {
*/
@Override
protected LoraMessageType getMessageType(final JsonObject loraMessage) {
return LoraMessageType.UPLINK;
if (loraMessage.containsKey(FIELD_TTN_PAYLOAD_RAW)) {
return LoraMessageType.UPLINK;
}
return LoraMessageType.UNKNOWN;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import org.eclipse.hono.adapter.lora.LoraCommand;
import org.eclipse.hono.adapter.lora.LoraMessageType;
import org.eclipse.hono.adapter.lora.UnknownLoraMessage;
import org.eclipse.hono.adapter.lora.UplinkLoraMessage;
import org.eclipse.hono.util.CommandEndpoint;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -65,7 +66,7 @@ public abstract class LoraProviderTestBase<T extends LoraProvider> {
*/
protected final RoutingContext getRequestContext(final LoraMessageType type, final String... classifiers) throws IOException {

final Buffer message = LoraTestUtil.loadTestFile(provider.getProviderName(), LoraMessageType.UPLINK, classifiers);
final Buffer message = LoraTestUtil.loadTestFile(provider.getProviderName(), type, classifiers);
final HttpServerRequest request = mock(HttpServerRequest.class);
final RoutingContext routingContext = mock(RoutingContext.class);
when(routingContext.request()).thenReturn(request);
Expand Down Expand Up @@ -99,6 +100,19 @@ public void testGetMessageSucceedsForUplinkMessage() throws IOException {
assertMetaDataForUplinkMessage(loraMessage);
}

/**
* Verifies that uplink messages are parsed correctly.
*
* @throws IOException If the file containing the example message could not be loaded.
*/
@Test
public void testGetMessageSucceedsForUnknownMessage() throws IOException {

final RoutingContext request = getRequestContext(LoraMessageType.UNKNOWN);
final UnknownLoraMessage loraMessage = (UnknownLoraMessage) provider.getMessage(request);
assertThat(loraMessage.getType()).isEqualTo(LoraMessageType.UNKNOWN);
}

/**
* Asserts presence of common properties in an uplink message.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"DevEUI_unknown": {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"DevEUI_unknown": {
}
}
42 changes: 42 additions & 0 deletions adapters/lora/src/test/resources/payload/chirpStack.unknown.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"applicationID": "123",
"applicationName": "temperature-sensor",
"deviceName": "garden-sensor",
"devEUI": "AgICAgICAgI=",
"devAddr": "AFE5Qg==",
"rxInfo": [
{
"gatewayID": "AwMDAwMDAwM=",
"time": "2019-11-08T13:59:25.048445Z",
"timeSinceGPSEpoch": null,
"rssi": -48,
"loRaSNR": 9,
"channel": 5,
"rfChain": 0,
"board": 0,
"antenna": 0,
"location": {
"latitude": 52.3740364,
"longitude": 4.9144401,
"altitude": 10.5
},
"fineTimestampType": "NONE",
"context": "9u/uvA==",
"uplinkID": "jhMh8Gq6RAOChSKbi83RHQ=="
}
],
"txInfo": {
"frequency": 868100000,
"modulation": "LORA",
"loRaModulationInfo": {
"bandwidth": 125,
"spreadingFactor": 11,
"codeRate": "4/5",
"polarizationInversion": false
}
},
"dr": 1,
"tags": {
"key": "value"
}
}
18 changes: 18 additions & 0 deletions adapters/lora/src/test/resources/payload/chirpStackV4.unknown.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"deduplicationId": "c9dbe358-2578-4fb7-b295-66b44edc45a6",
"time": "2022-07-18T09:33:28.823500726+00:00",
"deviceInfo": {
"tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242",
"tenantName": "ChirpStack",
"applicationId": "17c82e96-be03-4f38-aef3-f83d48582d97",
"applicationName": "Test application",
"deviceProfileId": "14855bf7-d10d-4aee-b618-ebfcb64dc7ad",
"deviceProfileName": "Test device-profile",
"deviceName": "Test device",
"devEui": "0101010101010101",
"tags": {
"key": "value"
}
},
"devAddr": "00189440"
}
18 changes: 18 additions & 0 deletions adapters/lora/src/test/resources/payload/everynet.unknown.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"meta": {
"network": "9e9bf02a",
"packet_hash": "adc6bcac0d06195bc0329c3ef6a2d6ea",
"application": "b3a1067cf7085309",
"time": 1504638900.866375,
"device": "8c30dd074be218cb",
"packet_id": "287f9555a3e8b000ffc8c3c50f60e309",
"gateway": "017e8cd996cd3a0e"
},
"params": {
"dev_eui": "8c30dd074be218cb",
"dev_addr": "01d6dcd6",
"dev_nonce": "f9e7",
"net_id": "000000"
},
"type": "join_request"
}
9 changes: 9 additions & 0 deletions adapters/lora/src/test/resources/payload/firefly.unknown.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"uid": "8a569133-aa44-4d7e-810d-af62faf9f722",
"type": "join_accept",
"received_at": "2016-07-15T14:31:11",
"frame_counter": null,
"for_frame_counter": null,
"direction": "down",
"device_eui": "2564927382738492"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}
2 changes: 2 additions & 0 deletions adapters/lora/src/test/resources/payload/kerlink.unknown.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}
Loading

0 comments on commit ff18da6

Please sign in to comment.