Example usage for io.netty.handler.codec.http HttpResponseStatus NO_CONTENT

List of usage examples for io.netty.handler.codec.http HttpResponseStatus NO_CONTENT

Introduction

In this page you can find the example usage for io.netty.handler.codec.http HttpResponseStatus NO_CONTENT.

Prototype

HttpResponseStatus NO_CONTENT

To view the source code for io.netty.handler.codec.http HttpResponseStatus NO_CONTENT.

Click Source Link

Document

204 No Content

Usage

From source file:co.cask.cdap.guides.BackLinksHandler.java

License:Apache License

@Path("backlink")
@POST/*from   w w w.j ava 2s .c o  m*/
public void handleBackLink(HttpServiceRequest request, HttpServiceResponder responder) {

    ByteBuffer requestContents = request.getContent();

    if (requestContents == null) {
        responder.sendError(HttpResponseStatus.NO_CONTENT.code(), "Request content is empty.");
        return;
    }

    if (parseAndStore(Charsets.UTF_8.decode(requestContents).toString().trim())) {
        responder.sendStatus(HttpResponseStatus.OK.code());
    } else {
        responder.sendError(HttpResponseStatus.BAD_REQUEST.code(), "Malformed backlink information");
    }
}

From source file:co.cask.cdap.guides.PageRankHandler.java

License:Apache License

@Path("pagerank")
@POST/*from w w w  .  j  av a  2  s .  c  om*/
public void handleBackLink(HttpServiceRequest request, HttpServiceResponder responder) {

    ByteBuffer requestContents = request.getContent();
    if (requestContents == null) {
        responder.sendError(HttpResponseStatus.NO_CONTENT.code(), "No URL provided.");
        return;
    }

    String urlParam = Charsets.UTF_8.decode(requestContents).toString();

    Double rank = pageRanks.read(urlParam);
    if (rank == null) {
        responder.sendError(HttpResponseStatus.NOT_FOUND.code(),
                "The following URL was not found: " + urlParam);
        return;
    }

    responder.sendJson(String.valueOf(rank));
}

From source file:com.beeswax.hexbid.handler.BidHandler.java

License:Apache License

/**
 * /*from w  ww. j  a  v  a  2  s.c o m*/
 * Process full bid request with following error codes:</br>
 * </br>
 * 200 if it sets bid price in {@link BidAgentResponse} successfully.</br>
 * 204 if no bid is made for this request</br>
 * 400 if there is a parsing error {@link BidAgentRequest} or it fails to get bidding strategy.</br>
 * 500 if server experienced an error.</br>
 * 
 * @param ChannelHandlerContext
 * 
 * @return FullHttpResponse
 * 
 */
public FullHttpResponse processRequest(ChannelHandlerContext ctx, FullHttpRequest request) {
    LOGGER.debug("/bid request");

    try {
        final BidAgentRequest bidRequest = (BidAgentRequest) BidProtobufParser
                .parseProtoBytebuf(request.content(), BidAgentRequest.newBuilder());
        final Optional<BidAgentResponse> bidResponse = bidder.SetBid(bidRequest);

        if (!bidResponse.isPresent()) {
            LOGGER.debug("No Bid");
            return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NO_CONTENT);
        }

        final FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                HttpResponseStatus.OK, Unpooled.wrappedBuffer(bidResponse.get().toByteArray()));
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, new AsciiString("application/x-protobuf"));
        return response;

    } catch (InvalidProtocolBufferException | IllegalArgumentException e) {
        return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST,
                Unpooled.wrappedBuffer("Bad request".getBytes()));
    } catch (Exception e) {
        LOGGER.error("Unexpected error when setting bid", e);
        return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR,
                Unpooled.wrappedBuffer("Internal error when setting bid".getBytes()));
    }
}

From source file:com.beeswax.hexbid.handler.BidHandlerTest.java

License:Apache License

@Test
public void processRequestTest_NoAdcandidate() {
    final BidAgentRequest.Builder requestBuilder = BidAgentRequest.newBuilder();
    final ByteBuf requestByteBuf = Unpooled.wrappedBuffer(requestBuilder.build().toByteArray());
    final FullHttpRequest request = Mockito.mock(FullHttpRequest.class);
    Mockito.when(request.content()).thenReturn(requestByteBuf);

    final ChannelHandlerContext ctx = Mockito.mock(ChannelHandlerContext.class);
    final BidHandler handler = new BidHandler();
    final FullHttpResponse response = handler.processRequest(ctx, request);
    Assert.assertEquals(HttpResponseStatus.NO_CONTENT, response.status());
    Assert.assertEquals(0, response.content().readableBytes());
}

From source file:com.chiorichan.http.HttpHandler.java

License:Mozilla Public License

/**
 * Handles the HTTP request. Each HTTP subsystem will be explicitly activated until a resolve is determined.
 *
 * @throws IOException/* ww w.  j a  v  a  2 s . c  o  m*/
 *              Universal exception for all Input/Output errors
 * @throws HttpError
 *              for HTTP Errors
 * @throws PermissionException
 *              for permission problems, like access denied
 * @throws MultipleException
 *              for multiple Scripting Factory Evaluation Exceptions
 * @throws ScriptingException
 *              for Scripting Factory Evaluation Exception
 * @throws SessionException
 *              for problems initializing a new or used session
 */
private void handleHttp() throws Exception // IOException, HttpError, SiteException, PermissionException, MultipleException, ScriptingException, SessionException
{
    log.log(Level.INFO, request.methodString() + " " + request.getFullUrl());

    Session sess = request.startSession();

    log.log(Level.FINE, "Session {id=%s,timeout=%s,new=%s}", sess.getSessId(), sess.getTimeout(), sess.isNew());

    if (response.getStage() == HttpResponseStage.CLOSED)
        throw new IOException("Connection reset by peer"); // This is not the only place 'Connection reset by peer' is thrown

    RequestEvent requestEvent = new RequestEvent(request);

    try {
        EventBus.instance().callEventWithException(requestEvent);
    } catch (EventException ex) {
        throw new IOException(
                "Exception encountered during request event call, most likely the fault of a plugin.", ex);
    }

    response.setStatus(requestEvent.getStatus());

    if (requestEvent.isCancelled()) {
        int status = requestEvent.getStatus();
        String reason = requestEvent.getReason();

        if (status == 200) {
            status = 502;
            reason = "Navigation Cancelled by Plugin Event";
        }

        NetworkManager.getLogger().warning("Navigation was cancelled by a Plugin Event");

        throw new HttpError(status, reason);
    }

    if (response.isCommitted())
        return;

    // Throws IOException and HttpError
    fi = new WebInterpreter(request);
    response.annotations.putAll(fi.getAnnotations());

    currentSite = request.getLocation();
    sess.setSite(currentSite);

    if (request.getSubdomain().length() > 0
            && !currentSite.getSubdomain(request.getSubdomain()).isMaped(request.getDomain())) {
        if ("www".equalsIgnoreCase(request.getSubdomain())
                || AppConfig.get().getBoolean("sites.redirectMissingSubDomains")) {
            log.log(Level.SEVERE, "Redirecting non-existent subdomain '%s' to root domain '%s'",
                    request.getSubdomain(), request.getFullUrl(""));
            response.sendRedirect(request.getFullUrl(""));
        } else {
            log.log(Level.SEVERE, "The requested subdomain '%s' is non-existent.", request.getSubdomain(),
                    request.getFullDomain(""));
            response.sendError(HttpResponseStatus.NOT_FOUND, "Subdomain not found");
        }
        return;
    }

    File docRoot = currentSite.getSubdomain(request.getSubdomain()).directory();

    Validate.notNull(docRoot);

    if (sess.isLoginPresent())
        log.log(Level.FINE, "Account {id=%s,displayName=%s}", sess.getId(), sess.getDisplayName());

    /*
     * Start: SSL enforcer
     *
     * Acts on the value of annotation 'SSL'.
     * REQUIRED means a forbidden error will be thrown is it can not be accomplished
     *
     * Options include:
     * Preferred: If SSL is available, we preferred to be switched to it
     * PostOnly: SSL is REQUIRED is this is a POST request
     * GetOnly: SSL is REQUIRED if this is a GET request
     * Required: SSL is REQUIRED, no exceptions!
     * Deny: SSL is DENIED, no exceptions!
     * Ignore: We don't care one way or other, do nothing! DEFAULT
     */
    SslLevel sslLevel = SslLevel.parse(fi.get("ssl"));
    boolean required = false;

    switch (sslLevel) {
    case Preferred:
        if (NetworkManager.isHttpsRunning())
            required = true;
        break;
    case PostOnly:
        if (request.method() == HttpMethod.POST)
            required = true;
        break;
    case GetOnly:
        if (request.method() == HttpMethod.GET)
            required = true;
        break;
    case Required:
        required = true;
        break;
    case Deny:
        if (ssl) {
            if (!response.switchToUnsecure())
                response.sendError(HttpCode.HTTP_FORBIDDEN, "This page requires an unsecure connection.");
            return;
        }
        break;
    case Ignore:
        break;
    }

    if (required && !ssl) {
        if (!response.switchToSecure())
            response.sendError(HttpCode.HTTP_FORBIDDEN, "This page requires a secure connection.");
        return;
    }
    /*
     * End: SSL enforcer
     */

    if (fi.getStatus() != HttpResponseStatus.OK)
        throw new HttpError(fi.getStatus());

    /*
     * Start: Apache Configuration Section
     *
     * Loads a Apache configuration and .htaccess files into a common handler, then parsed for directives like access restrictions and basic auth
     * TODO Load server-wide Apache Configuration then merge with Site Configuration
     */
    ApacheHandler htaccess = new ApacheHandler();
    response.setApacheParser(htaccess);

    try {
        boolean result = htaccess.handleDirectives(currentSite.getApacheConfig(), this);

        if (htaccess.overrideNone() || htaccess.overrideListNone()) // Ignore .htaccess files
        {
            if (fi.hasFile())
                if (!htaccess.handleDirectives(new ApacheConfiguration(fi.getFile().getParentFile()), this))
                    result = false;

            if (!htaccess.handleDirectives(new ApacheConfiguration(docRoot), this))
                result = false;
        }

        if (!result) {
            if (!response.isCommitted())
                response.sendError(500,
                        "Your request was blocked by an internal configuration directive, exact details are unknown.");
            return;
        }
    } catch (ApacheDirectiveException e) {
        log.log(Level.SEVERE, "Caught Apache directive exception: " + e.getMessage());

        // TODO Throw 500 unless told not to
    }
    /*
     * End: Apache Configuration Section
     */

    if (!fi.hasFile() && !fi.hasHTML())
        response.setStatus(HttpResponseStatus.NO_CONTENT);

    sess.setGlobal("__FILE__", fi.getFile());

    request.putRewriteParams(fi.getRewriteParams());
    response.setContentType(fi.getContentType());
    response.setEncoding(fi.getEncoding());

    request.getServer().put(ServerVars.DOCUMENT_ROOT, docRoot);

    request.setGlobal("_SERVER", request.getServer());
    request.setGlobal("_POST", request.getPostMap());
    request.setGlobal("_GET", request.getGetMap());
    request.setGlobal("_REWRITE", request.getRewriteMap());
    request.setGlobal("_FILES", request.getUploadedFiles());

    // TODO Implement NONCE requirement for login page
    NonceLevel level = NonceLevel.parse(fi.get("nonce"));
    boolean nonceProvided = sess.nonce() == null ? false
            : request.getRequestMap().get(sess.nonce().key()) != null;
    boolean processNonce = false;

    switch (level) {
    case Required:
        processNonce = true;
        break;
    case GetOnly:
        processNonce = request.method() == HttpMethod.GET || nonceProvided;
        break;
    case PostOnly:
        processNonce = request.method() == HttpMethod.POST || nonceProvided;
        break;
    case Flexible:
        processNonce = nonceProvided;
        break;
    case Disabled:
    default:
        // Do Nothing
    }

    Map<String, String> nonceMap = Maps.newHashMap();

    if (processNonce) {
        if (!nonceProvided) {
            log.log(Level.SEVERE,
                    "The request has failed NONCE validation, because the nonce key was not present!");
            response.sendError(HttpResponseStatus.FORBIDDEN, "Your request has failed NONCE validation!");
            return;
        }

        Nonce nonce = sess.nonce();

        if (level == NonceLevel.Required)
            // Required NonceLevels are of the highest protected state
            sess.destroyNonce();

        try {
            if (!(request.getRequestMap().get(nonce.key()) instanceof String))
                throw new NonceException("Nonce token is not a string");
            nonce.validateWithException((String) request.getRequestMap().get(nonce.key()));
        } catch (NonceException e) {
            log.log(Level.SEVERE,
                    "The request has failed NONCE validation, because " + e.getMessage().toLowerCase() + "!");
            response.sendError(HttpResponseStatus.FORBIDDEN, "Your request has failed NONCE validation!");
            sess.destroyNonce();
            return;
        } finally {
            log.log(Level.INFO, "The request has passed the NONCE validation!");
            request.nonceProcessed(true);
            nonceMap = nonce.mapValues();
        }
    }

    if (request.validateLogins())
        return;

    if (level != NonceLevel.Disabled)
        request.setGlobal("_NONCE", nonceMap);

    try {
        if (request.getUploadedFiles().size() > 0)
            log.log(Level.INFO,
                    "Uploads {"
                            + StringFunc.limitLength(
                                    Joiner.on(",").skipNulls().join(request.getUploadedFiles().values()), 255)
                            + "}");

        if (request.getGetMap().size() > 0)
            log.log(Level.INFO, "Params GET {" + StringFunc.limitLength(
                    Joiner.on(",").withKeyValueSeparator("=").useForNull("null").join(request.getGetMap()), 255)
                    + "}");

        if (request.getPostMap().size() > 0)
            log.log(Level.INFO, "Params POST {" + StringFunc.limitLength(
                    Joiner.on(",").withKeyValueSeparator("=").useForNull("null").join(request.getPostMap()),
                    255) + "}");

        if (request.getRewriteMap().size() > 0)
            log.log(Level.INFO, "Params REWRITE {" + StringFunc.limitLength(
                    Joiner.on(",").withKeyValueSeparator("=").useForNull("null").join(request.getRewriteMap()),
                    255) + "}");

        if (fi.getAnnotations().size() > 0)
            log.log(Level.INFO, "Params ANNOTATIONS {" + StringFunc.limitLength(
                    Joiner.on(",").withKeyValueSeparator("=").useForNull("null").join(fi.getAnnotations()), 255)
                    + "}");
    } catch (Throwable t) {
        t.printStackTrace();
    }

    if (AppConfig.get().getBoolean("advanced.security.requestMapEnabled", true))
        request.setGlobal("_REQUEST", request.getRequestMap());

    ByteBuf rendered = Unpooled.buffer();

    ScriptingFactory factory = request.getEvalFactory();
    factory.setEncoding(fi.getEncoding());

    NetworkSecurity.isForbidden(htaccess, currentSite, fi);

    String req = fi.get("reqperm");

    if (req == null)
        req = "-1";

    sess.requirePermission(req, currentSite.getId());

    // Enhancement: Allow HTML to be ran under different shells. Default is embedded.
    if (fi.hasHTML()) {
        ScriptingResult result = factory.eval(
                ScriptingContext.fromSource(fi.getHTML(), "<embedded>").request(request).site(currentSite));

        if (result.hasExceptions())
            // TODO Print notices to output like PHP does
            for (ScriptingException e : result.getExceptions()) {
                ExceptionReport.throwExceptions(e);
                log.exceptions(e);
                if (e.reportingLevel().isEnabled())
                    rendered.writeBytes(e.getMessage().getBytes());
            }

        if (result.isSuccessful()) {
            rendered.writeBytes(result.content());
            if (result.getObject() != null && !(result.getObject() instanceof NullObject))
                try {
                    rendered.writeBytes(ObjectFunc.castToStringWithException(result.getObject()).getBytes());
                } catch (Exception e) {
                    log.log(Level.SEVERE, "Exception Excountered: %s", e.getMessage());
                    if (Versioning.isDevelopment())
                        log.log(Level.SEVERE, e.getStackTrace()[0].toString());
                }
        }

        log.log(Level.INFO, "EvalHtml {timing=%sms,success=%s}", Timings.mark(this), result.isSuccessful());
    }

    if (fi.hasFile()) {
        if (fi.isDirectoryRequest()) {
            processDirectoryListing();
            return;
        }

        ScriptingResult result = factory.eval(ScriptingContext.fromFile(fi).request(request).site(currentSite));

        if (result.hasExceptions())
            // TODO Print notices to output like PHP does
            for (ScriptingException e : result.getExceptions()) {
                ExceptionReport.throwExceptions(e);
                log.exceptions(e);
                if (e.reportingLevel().isEnabled() && e.getMessage() != null)
                    rendered.writeBytes(e.getMessage().getBytes());
            }

        if (result.isSuccessful()) {
            rendered.writeBytes(result.content());
            if (result.getObject() != null && !(result.getObject() instanceof NullObject))
                try {
                    rendered.writeBytes(ObjectFunc.castToStringWithException(result.getObject()).getBytes());
                } catch (Exception e) {
                    rendered.writeBytes(result.getObject().toString().getBytes());
                    log.log(Level.SEVERE, "Exception encountered while writing returned object to output. %s",
                            e.getMessage());
                    if (Versioning.isDevelopment())
                        log.log(Level.SEVERE, e.getStackTrace()[0].toString());
                }
        }

        log.log(Level.INFO, "EvalFile {file=%s,timing=%sms,success=%s}", fi.getFilePath(), Timings.mark(this),
                result.isSuccessful());
    }

    // if the connection was in a MultiPart mode, wait for the mode to change then return gracefully.
    if (response.stage == HttpResponseStage.MULTIPART) {
        while (response.stage == HttpResponseStage.MULTIPART)
            // I wonder if there is a better way to handle multipart responses.
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new HttpError(500, "Internal Server Error encountered during multipart execution.");
            }

        return;
    }
    // If the connection was closed from page redirect, return gracefully.
    else if (response.stage == HttpResponseStage.CLOSED || response.stage == HttpResponseStage.WRITTEN)
        return;

    // Allows scripts to directly override interpreter values. For example: Themes, Views, Titles
    for (Entry<String, String> kv : response.annotations.entrySet())
        fi.put(kv.getKey(), kv.getValue());

    RenderEvent renderEvent = new RenderEvent(this, rendered, fi.getEncoding(), fi.getAnnotations());

    try {
        EventBus.instance().callEventWithException(renderEvent);
        if (renderEvent.getSource() != null)
            rendered = renderEvent.getSource();
    } catch (EventException ex) {
        throw new ScriptingException(ReportingLevel.E_ERROR,
                "Caught EventException while trying to fire the RenderEvent", ex.getCause());
    }

    log.log(Level.INFO, "Written {bytes=%s,total_timing=%sms}", rendered.readableBytes(), Timings.finish(this));

    try {
        response.write(rendered);
    } catch (IllegalReferenceCountException e) {
        log.log(Level.SEVERE, "Exception encountered while writting script object to output, %s",
                e.getMessage());
    }
}

From source file:com.google.devtools.build.lib.remote.blobstore.http.HttpBlobStore.java

License:Open Source License

private boolean cacheMiss(HttpResponseStatus status) {
    // Supporting NO_CONTENT for nginx webdav compatibility.
    return status.equals(HttpResponseStatus.NOT_FOUND) || status.equals(HttpResponseStatus.NO_CONTENT);
}

From source file:com.google.devtools.build.lib.remote.blobstore.http.HttpUploadHandler.java

License:Open Source License

@SuppressWarnings("FutureReturnValueIgnored")
@Override//w  w w . j  a v a2 s . c  o m
protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse response) {
    if (!response.decoderResult().isSuccess()) {
        failAndClose(new IOException("Failed to parse the HTTP response."), ctx);
        return;
    }
    try {
        checkState(userPromise != null, "response before request");
        if (!response.status().equals(HttpResponseStatus.OK)
                && !response.status().equals(HttpResponseStatus.ACCEPTED)
                && !response.status().equals(HttpResponseStatus.CREATED)
                && !response.status().equals(HttpResponseStatus.NO_CONTENT)) {
            // Supporting more than OK status to be compatible with nginx webdav.
            String errorMsg = response.status().toString();
            if (response.content().readableBytes() > 0) {
                byte[] data = new byte[response.content().readableBytes()];
                response.content().readBytes(data);
                errorMsg += "\n" + new String(data, HttpUtil.getCharset(response));
            }
            failAndResetUserPromise(new HttpException(response, errorMsg, null));
        } else {
            succeedAndResetUserPromise();
        }
    } finally {
        if (!HttpUtil.isKeepAlive(response)) {
            ctx.close();
        }
    }
}

From source file:com.google.devtools.build.lib.remote.blobstore.http.HttpUploadHandlerTest.java

License:Open Source License

/**
 * Test that uploading blobs works to both the Action Cache and the CAS. Also test that the
 * handler is reusable.//from  w w  w . ja  va  2  s .  c  o m
 */
@Test
public void uploadsShouldWork() throws Exception {
    EmbeddedChannel ch = new EmbeddedChannel(new HttpUploadHandler(null));
    HttpResponseStatus[] statuses = new HttpResponseStatus[] { HttpResponseStatus.OK,
            HttpResponseStatus.CREATED, HttpResponseStatus.ACCEPTED, HttpResponseStatus.NO_CONTENT };

    for (HttpResponseStatus status : statuses) {
        uploadsShouldWork(true, ch, status);
        uploadsShouldWork(false, ch, status);
    }
}

From source file:com.google.devtools.build.remote.worker.HttpCacheServerHandler.java

License:Open Source License

private void handlePut(ChannelHandlerContext ctx, FullHttpRequest request) {
    if (!request.decoderResult().isSuccess()) {
        sendError(ctx, request, HttpResponseStatus.INTERNAL_SERVER_ERROR);
        return;//from   w w  w .j av  a 2s .co  m
    }

    byte[] contentBytes = new byte[request.content().readableBytes()];
    request.content().readBytes(contentBytes);
    cache.putIfAbsent(request.uri(), contentBytes);

    FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
            HttpResponseStatus.NO_CONTENT);
    ChannelFuture lastContentFuture = ctx.writeAndFlush(response);

    if (!HttpUtil.isKeepAlive(request)) {
        lastContentFuture.addListener(ChannelFutureListener.CLOSE);
    }
}

From source file:com.heliosapm.streams.onramp.HttpJsonRpcHandler.java

License:Apache License

/**
 * {@inheritDoc}/*from  w  ww . j  a  v  a 2 s.  c  o  m*/
 * @see io.netty.handler.codec.MessageToMessageDecoder#decode(io.netty.channel.ChannelHandlerContext, java.lang.Object, java.util.List)
 */
@Override
protected void decode(final ChannelHandlerContext ctx, final FullHttpRequest msg, final List<Object> out)
        throws Exception {
    int forwarded = 0;
    int nodes = 0;
    final ElapsedTime et = SystemClock.startClock();
    final ByteBuf buff = msg.content();
    if (buff.readableBytes() < 2) {
        log.info("Request from [{}] had no content: {}", ctx.channel().remoteAddress(), buff);
        // send response
        return;
    }

    final ArrayList<ObjectNode> metricNodes = new ArrayList<ObjectNode>(256);
    final JsonNode rootNode = JSONOps.parseToNode(buff);
    if (rootNode.isArray()) {
        for (JsonNode node : rootNode) {
            if (node.has("metric")) {
                metricNodes.add((ObjectNode) node);
                nodes++;
                if (nodes == batchSize) {
                    try {
                        nodes = 0;
                        forwarded += forwardMetrics(metricNodes);
                    } finally {
                        metricNodes.clear();
                    }
                }
            }
        }
        if (!metricNodes.isEmpty())
            try {
                nodes += metricNodes.size();
                forwarded += forwardMetrics(metricNodes);
            } finally {
                metricNodes.clear();
            }
    } else {
        if (rootNode.has("metric")) {
            forwarded += forwardMetrics(Collections.singletonList((ObjectNode) rootNode));
        }
    }
    ctx.channel().pipeline()
            .writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NO_CONTENT));
    log.info("Wrote [{}] metrics: {}", forwarded, et.printAvg("Metrics", forwarded));
}