Skip to content

Commit

Permalink
Add support for custom COAP requests logging
Browse files Browse the repository at this point in the history
  • Loading branch information
akolosov-n committed Sep 3, 2024
1 parent 7fd3715 commit 9a3407a
Show file tree
Hide file tree
Showing 8 changed files with 318 additions and 102 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2022-2024 java-coap contributors (https://github.com/open-coap/java-coap)
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mbed.coap.server;

import com.mbed.coap.packet.CoapRequest;
import com.mbed.coap.packet.CoapResponse;
import com.mbed.coap.utils.Filter;
import com.mbed.coap.utils.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.slf4j.event.Level;
import org.slf4j.spi.LoggingEventBuilder;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.function.Function;

public class CoapRequestLogger implements Filter.SimpleFilter<CoapRequest, CoapResponse> {
private final LoggingEventBuilder loggingEventBuilder;
private final BiFunction<CoapRequest, CoapResponse, String> formatter;
private final Map<String, Function<CoapRequest, String>> mdcUpdaters;

public CoapRequestLogger(Logger logger, Level level, BiFunction<CoapRequest, CoapResponse, String> formatter, Map<String, Function<CoapRequest, String>> mdcUpdaters) {
this.loggingEventBuilder = logger.atLevel(level);
this.formatter = formatter;
this.mdcUpdaters = mdcUpdaters;
}

@Override
public CompletableFuture<CoapResponse> apply(CoapRequest req, Service<CoapRequest, CoapResponse> service) {
mdcUpdaters.forEach((key, updater) -> MDC.put(key, updater.apply(req)));
return service.apply(req).thenApply((resp) -> {
loggingEventBuilder.log(() -> formatter.apply(req, resp));
mdcUpdaters.forEach((key, ___) -> MDC.remove(key));
return resp;
});
}

public static CoapRequestLoggerBuilder builder() {
return new CoapRequestLoggerBuilder();

Check warning on line 56 in coap-core/src/main/java/com/mbed/coap/server/CoapRequestLogger.java

View check run for this annotation

Codecov / codecov/patch

coap-core/src/main/java/com/mbed/coap/server/CoapRequestLogger.java#L56

Added line #L56 was not covered by tests
}

public static class CoapRequestLoggerBuilder {
private Logger logger = LoggerFactory.getLogger(CoapRequestLogger.class);
private Level level = Level.INFO;
private BiFunction<CoapRequest, CoapResponse, String> formatter = (req, resp) -> req.toString() + " -> " + resp.toString();
private final Map<String, Function<CoapRequest, String>> mdcUpdaters = new HashMap<>();

public CoapRequestLoggerBuilder logger(Logger logger) {
this.logger = logger;
return this;
}

public CoapRequestLoggerBuilder level(Level level) {
this.level = level;
return this;
}

public CoapRequestLoggerBuilder formatter(BiFunction<CoapRequest, CoapResponse, String> formatter) {
this.formatter = formatter;
return this;
}

public CoapRequestLoggerBuilder mdc(String key, Function<CoapRequest, String> updater) {
mdcUpdaters.put(key, updater);
return this;
}

public CoapRequestLogger build() {
return new CoapRequestLogger(logger, level, formatter, mdcUpdaters);
}
}
}
53 changes: 26 additions & 27 deletions coap-core/src/main/java/com/mbed/coap/server/CoapServerBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,24 @@
*/
package com.mbed.coap.server;

import static com.mbed.coap.transport.CoapTransport.logSent;
import static com.mbed.coap.transport.TransportContext.RESPONSE_TIMEOUT;
import static com.mbed.coap.utils.Timer.toTimer;
import static com.mbed.coap.utils.Validations.require;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
import com.mbed.coap.client.CoapClient;
import com.mbed.coap.packet.BlockSize;
import com.mbed.coap.packet.CoapPacket;
import com.mbed.coap.packet.CoapRequest;
import com.mbed.coap.packet.CoapResponse;
import com.mbed.coap.packet.SeparateResponse;
import com.mbed.coap.packet.*;
import com.mbed.coap.server.block.BlockWiseIncomingFilter;
import com.mbed.coap.server.block.BlockWiseNotificationFilter;
import com.mbed.coap.server.block.BlockWiseOutgoingFilter;
import com.mbed.coap.server.filter.CongestionControlFilter;
import com.mbed.coap.server.filter.EchoFilter;
import com.mbed.coap.server.filter.ResponseTimeoutFilter;
import com.mbed.coap.server.messaging.Capabilities;
import com.mbed.coap.server.messaging.CapabilitiesResolver;
import com.mbed.coap.server.messaging.CoapDispatcher;
import com.mbed.coap.server.messaging.CoapRequestConverter;
import com.mbed.coap.server.messaging.DuplicateDetector;
import com.mbed.coap.server.messaging.ExchangeFilter;
import com.mbed.coap.server.messaging.MessageIdSupplier;
import com.mbed.coap.server.messaging.MessageIdSupplierImpl;
import com.mbed.coap.server.messaging.ObservationMapper;
import com.mbed.coap.server.messaging.PiggybackedExchangeFilter;
import com.mbed.coap.server.messaging.RequestTagSupplier;
import com.mbed.coap.server.messaging.RetransmissionFilter;
import com.mbed.coap.server.messaging.*;
import com.mbed.coap.server.observe.NotificationsReceiver;
import com.mbed.coap.server.observe.ObservationsStore;
import com.mbed.coap.transmission.RetransmissionBackOff;
import com.mbed.coap.transport.CoapTransport;
import com.mbed.coap.transport.LoggingCoapTransport;
import com.mbed.coap.utils.Filter;
import com.mbed.coap.utils.Service;
import com.mbed.coap.utils.Timer;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.time.Duration;
Expand All @@ -62,6 +43,12 @@
import java.util.function.Supplier;
import java.util.stream.Stream;

import static com.mbed.coap.transport.TransportContext.RESPONSE_TIMEOUT;
import static com.mbed.coap.utils.Timer.toTimer;
import static com.mbed.coap.utils.Validations.require;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;

public final class CoapServerBuilder {
private static final long DELAYED_TRANSACTION_TIMEOUT_MS = 120000; //2 minutes

Expand All @@ -80,9 +67,11 @@ public final class CoapServerBuilder {
private int maxQueueSize = 100;
private Filter.SimpleFilter<CoapRequest, CoapResponse> outboundFilter = Filter.identity();
private Filter.SimpleFilter<CoapRequest, CoapResponse> routeFilter = Filter.identity();
private Filter.SimpleFilter<CoapRequest, CoapResponse> requestFilter = Filter.identity();
private NotificationsReceiver notificationsReceiver = NotificationsReceiver.REJECT_ALL;
private ObservationsStore observationStore = ObservationsStore.ALWAYS_EMPTY;
private RequestTagSupplier requestTagSupplier = RequestTagSupplier.createSequential();
private Boolean isTransportLoggingEnabled = true;

CoapServerBuilder() {
}
Expand Down Expand Up @@ -118,6 +107,11 @@ public CoapServerBuilder routeFilter(Filter.SimpleFilter<CoapRequest, CoapRespon
return this;
}

public CoapServerBuilder requestFilter(Filter.SimpleFilter<CoapRequest, CoapResponse> requestFilter) {
this.requestFilter = requireNonNull(requestFilter);
return this;

Check warning on line 112 in coap-core/src/main/java/com/mbed/coap/server/CoapServerBuilder.java

View check run for this annotation

Codecov / codecov/patch

coap-core/src/main/java/com/mbed/coap/server/CoapServerBuilder.java#L111-L112

Added lines #L111 - L112 were not covered by tests
}

public CoapServerBuilder outboundFilter(Filter.SimpleFilter<CoapRequest, CoapResponse> outboundFilter) {
this.outboundFilter = requireNonNull(outboundFilter);
return this;
Expand Down Expand Up @@ -216,14 +210,19 @@ public CoapServerBuilder requestTagSupplier(RequestTagSupplier requestTagSupplie
return this;
}

public CoapServerBuilder transportLogging(Boolean transportLogging) {
this.isTransportLoggingEnabled = requireNonNull(transportLogging);
return this;

Check warning on line 215 in coap-core/src/main/java/com/mbed/coap/server/CoapServerBuilder.java

View check run for this annotation

Codecov / codecov/patch

coap-core/src/main/java/com/mbed/coap/server/CoapServerBuilder.java#L214-L215

Added lines #L214 - L215 were not covered by tests
}

public CoapServer build() {
CoapTransport coapTransport = requireNonNull(this.coapTransport.get(), "Missing transport");
CoapTransport realTransport = requireNonNull(this.coapTransport.get(), "Missing transport");
CoapTransport coapTransport = isTransportLoggingEnabled ? new LoggingCoapTransport(realTransport) : realTransport;
final boolean stopExecutor = scheduledExecutorService == null;
final ScheduledExecutorService effectiveExecutorService = scheduledExecutorService != null ? scheduledExecutorService : Executors.newSingleThreadScheduledExecutor();
Timer timer = toTimer(effectiveExecutorService);

Service<CoapPacket, Boolean> sender = packet -> coapTransport.sendPacket(packet)
.whenComplete((__, throwable) -> logSent(packet, throwable));
Service<CoapPacket, Boolean> sender = coapTransport::sendPacket;

// OUTBOUND
ExchangeFilter exchangeFilter = new ExchangeFilter();
Expand Down Expand Up @@ -259,6 +258,7 @@ public CoapServer build() {
DuplicateDetector duplicateDetector = new DuplicateDetector(duplicateDetectorCache, duplicatedCoapMessageCallback);
Service<CoapPacket, CoapPacket> inboundService = duplicateDetector
.andThen(new CoapRequestConverter(midSupplier))
.andThen(requestFilter)
.andThen(new RescueFilter())
.andThen(new CriticalOptionVerifier())
.andThen(new BlockWiseIncomingFilter(capabilities(), maxIncomingBlockTransferSize))
Expand Down Expand Up @@ -295,5 +295,4 @@ public CoapServerGroup buildGroup(int size) {

return new CoapServerGroup(servers);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,19 @@
*/
package com.mbed.coap.server.messaging;

import static com.mbed.coap.transport.CoapTransport.logReceived;
import static com.mbed.coap.utils.FutureHelpers.logError;
import static com.mbed.coap.utils.FutureHelpers.logErrorIgnoreCancelled;
import static java.util.Objects.requireNonNull;
import com.mbed.coap.packet.CoapPacket;
import com.mbed.coap.packet.MessageType;
import com.mbed.coap.packet.SeparateResponse;
import com.mbed.coap.utils.Service;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.function.Function;

import static com.mbed.coap.utils.FutureHelpers.logError;
import static com.mbed.coap.utils.FutureHelpers.logErrorIgnoreCancelled;
import static java.util.Objects.requireNonNull;

public final class CoapDispatcher {

private static final Logger LOGGER = LoggerFactory.getLogger(CoapDispatcher.class);
Expand All @@ -38,8 +39,8 @@ public final class CoapDispatcher {
private final Function<SeparateResponse, Boolean> handleSeparateResponse;

public CoapDispatcher(Service<CoapPacket, Boolean> sender,
Service<CoapPacket, CoapPacket> observationHandler, Service<CoapPacket, CoapPacket> inboundService,
Function<CoapPacket, Boolean> handleResponse, Function<SeparateResponse, Boolean> handleSeparateResponse) {
Service<CoapPacket, CoapPacket> observationHandler, Service<CoapPacket, CoapPacket> inboundService,
Function<CoapPacket, Boolean> handleResponse, Function<SeparateResponse, Boolean> handleSeparateResponse) {

this.sender = sender;
this.observationHandler = requireNonNull(observationHandler);
Expand All @@ -49,7 +50,6 @@ public CoapDispatcher(Service<CoapPacket, Boolean> sender,
}

public void handle(CoapPacket packet) {
logReceived(packet);
if (handlePing(packet)) {
return;
}
Expand Down
35 changes: 3 additions & 32 deletions coap-core/src/main/java/com/mbed/coap/transport/CoapTransport.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
*
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand All @@ -16,15 +16,12 @@
package com.mbed.coap.transport;

import com.mbed.coap.packet.CoapPacket;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public interface CoapTransport {
Logger LOGGER = LoggerFactory.getLogger(CoapTransport.class);

void start() throws IOException;

void stop();
Expand All @@ -34,30 +31,4 @@ public interface CoapTransport {
CompletableFuture<CoapPacket> receive();

InetSocketAddress getLocalSocketAddress();

static void logSent(CoapPacket packet, Throwable maybeError) {
if (maybeError != null) {
LOGGER.warn("[{}] CoAP sent failed [{}] {}", packet.getRemoteAddrString(), packet.toString(false, false, false, true), maybeError.toString());
return;
}

if (LOGGER.isTraceEnabled()) {
LOGGER.trace("CoAP sent [{}]", packet.toString(true));
} else if (LOGGER.isDebugEnabled()) {
LOGGER.debug("CoAP sent [{}]", packet.toString(false));
} else if (LOGGER.isInfoEnabled()) {
LOGGER.info("[{}] CoAP sent [{}]", packet.getRemoteAddrString(), packet.toString(false, false, false, true));
}
}

static void logReceived(CoapPacket packet) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("CoAP received [{}]", packet.toString(true));
} else if (LOGGER.isDebugEnabled()) {
LOGGER.debug("[{}] CoAP received [{}]", packet.getRemoteAddrString(), packet.toString(false));
} else if (LOGGER.isInfoEnabled()) {
LOGGER.info("[{}] CoAP received [{}]", packet.getRemoteAddrString(), packet.toString(false, false, false, true));
}
}

}
Loading

0 comments on commit 9a3407a

Please sign in to comment.