Moved packages from old io.moquette.server to new io.moquette.broker
This commit is contained in:
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2016 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
package io.moquette.server.netty;
|
||||
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.util.concurrent.EventExecutor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Auto-flush data on channel after a read timeout. It's inspired by IdleStateHandler but it's
|
||||
* specialized version, just flushing data after no read is done on the channel after a period. It's
|
||||
* used to avoid aggressively flushing from the ProtocolProcessor.
|
||||
*/
|
||||
public class AutoFlushHandler extends ChannelDuplexHandler {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AutoFlushHandler.class);
|
||||
private static final long MIN_TIMEOUT_NANOS = TimeUnit.MILLISECONDS.toNanos(1);
|
||||
|
||||
private final long writerIdleTimeNanos;
|
||||
volatile ScheduledFuture<?> writerIdleTimeout;
|
||||
volatile long lastWriteTime;
|
||||
// private boolean firstWriterIdleEvent = true;
|
||||
|
||||
private volatile int state; // 0 - none, 1 - initialized, 2 - destroyed
|
||||
|
||||
public AutoFlushHandler(long writerIdleTime, TimeUnit unit) {
|
||||
if (unit == null) {
|
||||
throw new NullPointerException("unit");
|
||||
}
|
||||
writerIdleTimeNanos = Math.max(unit.toNanos(writerIdleTime), MIN_TIMEOUT_NANOS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
|
||||
if (ctx.channel().isActive() && ctx.channel().isRegistered()) {
|
||||
// channelActive() event has been fired already, which means this.channelActive() will
|
||||
// not be invoked. We have to initialize here instead.
|
||||
initialize(ctx);
|
||||
} else {
|
||||
// channelActive() event has not been fired yet. this.channelActive() will be invoked
|
||||
// and initialization will occur there.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlerRemoved(ChannelHandlerContext ctx) {
|
||||
destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
|
||||
// Initialize early if channel is active already.
|
||||
// if (ctx.channel().isActive()) {
|
||||
// initialize(ctx);
|
||||
// }
|
||||
super.channelRegistered(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
// This method will be invoked only if this handler was added
|
||||
// before channelActive() event is fired. If a user adds this handler
|
||||
// after the channelActive() event, initialize() will be called by beforeAdd().
|
||||
// initialize(ctx);
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
destroy();
|
||||
super.channelInactive(ctx);
|
||||
}
|
||||
|
||||
private void initialize(ChannelHandlerContext ctx) {
|
||||
// Avoid the case where destroy() is called before scheduling timeouts.
|
||||
// See: https://github.com/netty/netty/issues/143
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Initializing autoflush handler on channel {} Cid: {}", ctx.channel(),
|
||||
NettyUtils.clientID(ctx.channel()));
|
||||
}
|
||||
switch (state) {
|
||||
case 1:
|
||||
case 2:
|
||||
return;
|
||||
}
|
||||
|
||||
state = 1;
|
||||
|
||||
EventExecutor loop = ctx.executor();
|
||||
|
||||
lastWriteTime = System.nanoTime();
|
||||
writerIdleTimeout = loop.schedule(new WriterIdleTimeoutTask(ctx), writerIdleTimeNanos, TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
private void destroy() {
|
||||
state = 2;
|
||||
|
||||
if (writerIdleTimeout != null) {
|
||||
writerIdleTimeout.cancel(false);
|
||||
writerIdleTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called when the write timeout expire.
|
||||
*
|
||||
* @param ctx the channel context.
|
||||
*/
|
||||
private void channelIdle(ChannelHandlerContext ctx) {
|
||||
// ctx.fireUserEventTriggered(evt);
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Flushing idle Netty channel {} Cid: {}", ctx.channel(), NettyUtils.clientID(ctx.channel()));
|
||||
}
|
||||
ctx.channel().flush();
|
||||
}
|
||||
|
||||
private final class WriterIdleTimeoutTask implements Runnable {
|
||||
|
||||
private final ChannelHandlerContext ctx;
|
||||
|
||||
WriterIdleTimeoutTask(ChannelHandlerContext ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!ctx.channel().isOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// long lastWriteTime = IdleStateHandler.this.lastWriteTime;
|
||||
// long lastWriteTime = lastWriteTime;
|
||||
long nextDelay = writerIdleTimeNanos - (System.nanoTime() - lastWriteTime);
|
||||
if (nextDelay <= 0) {
|
||||
// Writer is idle - set a new timeout and notify the callback.
|
||||
writerIdleTimeout = ctx.executor().schedule(this, writerIdleTimeNanos, TimeUnit.NANOSECONDS);
|
||||
try {
|
||||
/*
|
||||
* IdleStateEvent event; if (firstWriterIdleEvent) { firstWriterIdleEvent =
|
||||
* false; event = IdleStateEvent.FIRST_WRITER_IDLE_STATE_EVENT; } else { event =
|
||||
* IdleStateEvent.WRITER_IDLE_STATE_EVENT; }
|
||||
*/
|
||||
channelIdle(ctx/* , event */);
|
||||
} catch (Throwable t) {
|
||||
ctx.fireExceptionCaught(t);
|
||||
}
|
||||
} else {
|
||||
// Write occurred before the timeout - set a new timeout with shorter delay.
|
||||
writerIdleTimeout = ctx.executor().schedule(this, nextDelay, TimeUnit.NANOSECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package io.moquette.server.netty;
|
||||
|
||||
import com.bugsnag.Bugsnag;
|
||||
import io.moquette.server.config.IConfig;
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
import static io.moquette.BrokerConstants.BUGSNAG_TOKEN_PROPERTY_NAME;
|
||||
|
||||
@Sharable
|
||||
public class BugSnagErrorsHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
private Bugsnag bugsnag;
|
||||
|
||||
public void init(IConfig props) {
|
||||
final String token = props.getProperty(BUGSNAG_TOKEN_PROPERTY_NAME);
|
||||
this.bugsnag = new Bugsnag(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
bugsnag.notify(cause);
|
||||
ctx.fireExceptionCaught(cause);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
package io.moquette.server.netty;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.timeout.IdleState;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
|
||||
import static io.netty.channel.ChannelFutureListener.CLOSE_ON_FAILURE;
|
||||
|
||||
@Sharable
|
||||
public class MoquetteIdleTimeoutHandler extends ChannelDuplexHandler {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MoquetteIdleTimeoutHandler.class);
|
||||
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||
if (evt instanceof IdleStateEvent) {
|
||||
IdleState e = ((IdleStateEvent) evt).state();
|
||||
if (e == IdleState.READER_IDLE) {
|
||||
LOG.info("Firing channel inactive event. MqttClientId = {}.", NettyUtils.clientID(ctx.channel()));
|
||||
// fire a close that then fire channelInactive to trigger publish of Will
|
||||
ctx.close().addListener(CLOSE_ON_FAILURE);
|
||||
}
|
||||
} else {
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Firing Netty event CId = {}, eventClass = {}", NettyUtils.clientID(ctx.channel()),
|
||||
evt.getClass().getName());
|
||||
}
|
||||
super.userEventTriggered(ctx, evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
package io.moquette.server.netty;
|
||||
|
||||
import io.moquette.server.Constants;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.util.Attribute;
|
||||
import io.netty.util.AttributeKey;
|
||||
|
||||
/**
|
||||
* Some Netty's channels utilities.
|
||||
*/
|
||||
public final class NettyUtils {
|
||||
|
||||
public static final String ATTR_USERNAME = "username";
|
||||
public static final String ATTR_SESSION_STOLEN = "sessionStolen";
|
||||
public static final String ATTR_CHANNEL_STATUS = "channelStatus";
|
||||
|
||||
private static final AttributeKey<Object> ATTR_KEY_KEEPALIVE = AttributeKey.valueOf(Constants.KEEP_ALIVE);
|
||||
private static final AttributeKey<Object> ATTR_KEY_CLEANSESSION = AttributeKey.valueOf(Constants.CLEAN_SESSION);
|
||||
private static final AttributeKey<Object> ATTR_KEY_CLIENTID = AttributeKey.valueOf(Constants.ATTR_CLIENTID);
|
||||
private static final AttributeKey<Object> ATTR_KEY_USERNAME = AttributeKey.valueOf(ATTR_USERNAME);
|
||||
|
||||
public static Object getAttribute(ChannelHandlerContext ctx, AttributeKey<Object> key) {
|
||||
Attribute<Object> attr = ctx.channel().attr(key);
|
||||
return attr.get();
|
||||
}
|
||||
|
||||
public static void keepAlive(Channel channel, int keepAlive) {
|
||||
channel.attr(NettyUtils.ATTR_KEY_KEEPALIVE).set(keepAlive);
|
||||
}
|
||||
|
||||
public static void cleanSession(Channel channel, boolean cleanSession) {
|
||||
channel.attr(NettyUtils.ATTR_KEY_CLEANSESSION).set(cleanSession);
|
||||
}
|
||||
|
||||
public static boolean cleanSession(Channel channel) {
|
||||
return (Boolean) channel.attr(NettyUtils.ATTR_KEY_CLEANSESSION).get();
|
||||
}
|
||||
|
||||
public static void clientID(Channel channel, String clientID) {
|
||||
channel.attr(NettyUtils.ATTR_KEY_CLIENTID).set(clientID);
|
||||
}
|
||||
|
||||
public static String clientID(Channel channel) {
|
||||
return (String) channel.attr(NettyUtils.ATTR_KEY_CLIENTID).get();
|
||||
}
|
||||
|
||||
public static void userName(Channel channel, String username) {
|
||||
channel.attr(NettyUtils.ATTR_KEY_USERNAME).set(username);
|
||||
}
|
||||
|
||||
public static String userName(Channel channel) {
|
||||
return (String) channel.attr(NettyUtils.ATTR_KEY_USERNAME).get();
|
||||
}
|
||||
|
||||
private NettyUtils() {
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
package io.moquette.server.netty.metrics;
|
||||
|
||||
public class BytesMetrics {
|
||||
|
||||
private long m_readBytes;
|
||||
private long m_wroteBytes;
|
||||
|
||||
void incrementRead(long numBytes) {
|
||||
m_readBytes += numBytes;
|
||||
}
|
||||
|
||||
void incrementWrote(long numBytes) {
|
||||
m_wroteBytes += numBytes;
|
||||
}
|
||||
|
||||
public long readBytes() {
|
||||
return m_readBytes;
|
||||
}
|
||||
|
||||
public long wroteBytes() {
|
||||
return m_wroteBytes;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
package io.moquette.server.netty.metrics;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Collects all the metrics from the various pipeline.
|
||||
*/
|
||||
public class BytesMetricsCollector {
|
||||
|
||||
private AtomicLong readBytes = new AtomicLong();
|
||||
private AtomicLong wroteBytes = new AtomicLong();
|
||||
|
||||
public BytesMetrics computeMetrics() {
|
||||
BytesMetrics allMetrics = new BytesMetrics();
|
||||
allMetrics.incrementRead(readBytes.get());
|
||||
allMetrics.incrementWrote(wroteBytes.get());
|
||||
return allMetrics;
|
||||
}
|
||||
|
||||
public void sumReadBytes(long count) {
|
||||
readBytes.getAndAdd(count);
|
||||
}
|
||||
|
||||
public void sumWroteBytes(long count) {
|
||||
wroteBytes.getAndAdd(count);
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
package io.moquette.server.netty.metrics;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.util.Attribute;
|
||||
import io.netty.util.AttributeKey;
|
||||
|
||||
import static io.netty.channel.ChannelFutureListener.CLOSE_ON_FAILURE;
|
||||
|
||||
public class BytesMetricsHandler extends ChannelDuplexHandler {
|
||||
|
||||
private static final AttributeKey<BytesMetrics> ATTR_KEY_METRICS = AttributeKey.valueOf("BytesMetrics");
|
||||
|
||||
private BytesMetricsCollector m_collector;
|
||||
|
||||
public BytesMetricsHandler(BytesMetricsCollector collector) {
|
||||
m_collector = collector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
Attribute<BytesMetrics> attr = ctx.channel().attr(ATTR_KEY_METRICS);
|
||||
attr.set(new BytesMetrics());
|
||||
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
BytesMetrics metrics = ctx.channel().attr(ATTR_KEY_METRICS).get();
|
||||
metrics.incrementRead(((ByteBuf) msg).readableBytes());
|
||||
ctx.fireChannelRead(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
BytesMetrics metrics = ctx.channel().attr(ATTR_KEY_METRICS).get();
|
||||
metrics.incrementWrote(((ByteBuf) msg).writableBytes());
|
||||
ctx.write(msg, promise).addListener(CLOSE_ON_FAILURE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
|
||||
BytesMetrics metrics = ctx.channel().attr(ATTR_KEY_METRICS).get();
|
||||
m_collector.sumReadBytes(metrics.readBytes());
|
||||
m_collector.sumWroteBytes(metrics.wroteBytes());
|
||||
super.close(ctx, promise);
|
||||
}
|
||||
|
||||
public static BytesMetrics getBytesMetrics(Channel channel) {
|
||||
return channel.attr(ATTR_KEY_METRICS).get();
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package io.moquette.server.netty.metrics;
|
||||
|
||||
import com.codahale.metrics.Counter;
|
||||
import com.codahale.metrics.Meter;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.librato.metrics.reporter.Librato;
|
||||
import io.moquette.server.config.IConfig;
|
||||
import io.moquette.server.netty.NettyUtils;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.codec.mqtt.MqttMessage;
|
||||
import io.netty.handler.codec.mqtt.MqttMessageType;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static io.moquette.BrokerConstants.*;
|
||||
import static io.netty.channel.ChannelHandler.Sharable;
|
||||
|
||||
/**
|
||||
* Pipeline handler use to track some MQTT metrics.
|
||||
*/
|
||||
@Sharable
|
||||
public final class DropWizardMetricsHandler extends ChannelInboundHandlerAdapter {
|
||||
private MetricRegistry metrics;
|
||||
private Meter publishesMetrics;
|
||||
private Meter subscribeMetrics;
|
||||
private Counter connectedClientsMetrics;
|
||||
|
||||
public void init(IConfig props) {
|
||||
this.metrics = new MetricRegistry();
|
||||
this.publishesMetrics = metrics.meter("publish.requests");
|
||||
this.subscribeMetrics = metrics.meter("subscribe.requests");
|
||||
this.connectedClientsMetrics = metrics.counter("connect.num_clients");
|
||||
// ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics)
|
||||
// .convertRatesTo(TimeUnit.SECONDS)
|
||||
// .convertDurationsTo(TimeUnit.MILLISECONDS)
|
||||
// .build();
|
||||
// reporter.start(1, TimeUnit.MINUTES);
|
||||
final String email = props.getProperty(METRICS_LIBRATO_EMAIL_PROPERTY_NAME);
|
||||
final String token = props.getProperty(METRICS_LIBRATO_TOKEN_PROPERTY_NAME);
|
||||
final String source = props.getProperty(METRICS_LIBRATO_SOURCE_PROPERTY_NAME);
|
||||
|
||||
Librato.reporter(this.metrics, email, token)
|
||||
.setSource(source)
|
||||
.start(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object message) {
|
||||
MqttMessage msg = (MqttMessage) message;
|
||||
MqttMessageType messageType = msg.fixedHeader().messageType();
|
||||
switch (messageType) {
|
||||
case PUBLISH:
|
||||
this.publishesMetrics.mark();
|
||||
break;
|
||||
case SUBSCRIBE:
|
||||
this.subscribeMetrics.mark();
|
||||
break;
|
||||
case CONNECT:
|
||||
this.connectedClientsMetrics.inc();
|
||||
break;
|
||||
case DISCONNECT:
|
||||
this.connectedClientsMetrics.dec();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ctx.fireChannelRead(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
String clientID = NettyUtils.clientID(ctx.channel());
|
||||
if (clientID != null && !clientID.isEmpty()) {
|
||||
this.connectedClientsMetrics.dec();
|
||||
}
|
||||
ctx.fireChannelInactive();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
package io.moquette.server.netty.metrics;
|
||||
|
||||
import io.moquette.server.netty.NettyUtils;
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.handler.codec.mqtt.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static io.moquette.spi.impl.Utils.messageId;
|
||||
import static io.netty.channel.ChannelFutureListener.CLOSE_ON_FAILURE;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
@Sharable
|
||||
public class MQTTMessageLogger extends ChannelDuplexHandler {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger("messageLogger");
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object message) throws Exception {
|
||||
logMQTTMessageRead(ctx, message);
|
||||
ctx.fireChannelRead(message);
|
||||
}
|
||||
|
||||
private void logMQTTMessageRead(ChannelHandlerContext ctx, Object message) throws Exception {
|
||||
logMQTTMessage(ctx, message, "C->B");
|
||||
}
|
||||
|
||||
private void logMQTTMessageWrite(ChannelHandlerContext ctx, Object message) throws Exception {
|
||||
logMQTTMessage(ctx, message, "C<-B");
|
||||
}
|
||||
|
||||
private void logMQTTMessage(ChannelHandlerContext ctx, Object message, String direction) throws Exception {
|
||||
if (!(message instanceof MqttMessage)) {
|
||||
return;
|
||||
}
|
||||
MqttMessage msg = (MqttMessage) message;
|
||||
if (msg.fixedHeader() == null) {
|
||||
throw new IOException("Unknown packet");
|
||||
}
|
||||
String clientID = NettyUtils.clientID(ctx.channel());
|
||||
MqttMessageType messageType = msg.fixedHeader().messageType();
|
||||
switch (messageType) {
|
||||
case CONNACK:
|
||||
case PINGREQ:
|
||||
case PINGRESP:
|
||||
LOG.debug("{} {} <{}>", direction, messageType, clientID);
|
||||
break;
|
||||
case CONNECT:
|
||||
case DISCONNECT:
|
||||
LOG.info("{} {} <{}>", direction, messageType, clientID);
|
||||
break;
|
||||
case SUBSCRIBE:
|
||||
MqttSubscribeMessage subscribe = (MqttSubscribeMessage) msg;
|
||||
LOG.info("{} SUBSCRIBE <{}> to topics {}", direction, clientID,
|
||||
subscribe.payload().topicSubscriptions());
|
||||
break;
|
||||
case UNSUBSCRIBE:
|
||||
MqttUnsubscribeMessage unsubscribe = (MqttUnsubscribeMessage) msg;
|
||||
LOG.info("{} UNSUBSCRIBE <{}> to topics <{}>", direction, clientID, unsubscribe.payload().topics());
|
||||
break;
|
||||
case PUBLISH:
|
||||
MqttPublishMessage publish = (MqttPublishMessage) msg;
|
||||
LOG.debug("{} PUBLISH <{}> to topics <{}>", direction, clientID, publish.variableHeader().topicName());
|
||||
break;
|
||||
case PUBREC:
|
||||
case PUBCOMP:
|
||||
case PUBREL:
|
||||
case PUBACK:
|
||||
case UNSUBACK:
|
||||
LOG.info("{} {} <{}> packetID <{}>", direction, messageType, clientID, messageId(msg));
|
||||
break;
|
||||
case SUBACK:
|
||||
MqttSubAckMessage suback = (MqttSubAckMessage) msg;
|
||||
final List<Integer> grantedQoSLevels = suback.payload().grantedQoSLevels();
|
||||
LOG.info("{} SUBACK <{}> packetID <{}>, grantedQoses {}", direction, clientID, messageId(msg),
|
||||
grantedQoSLevels);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
String clientID = NettyUtils.clientID(ctx.channel());
|
||||
if (clientID != null && !clientID.isEmpty()) {
|
||||
LOG.info("Channel closed <{}>", clientID);
|
||||
}
|
||||
ctx.fireChannelInactive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
logMQTTMessageWrite(ctx, msg);
|
||||
ctx.write(msg, promise).addListener(CLOSE_ON_FAILURE);
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
package io.moquette.server.netty.metrics;
|
||||
|
||||
public class MessageMetrics {
|
||||
|
||||
private long m_messagesRead;
|
||||
private long m_messageWrote;
|
||||
|
||||
void incrementRead(long numMessages) {
|
||||
m_messagesRead += numMessages;
|
||||
}
|
||||
|
||||
void incrementWrote(long numMessages) {
|
||||
m_messageWrote += numMessages;
|
||||
}
|
||||
|
||||
public long messagesRead() {
|
||||
return m_messagesRead;
|
||||
}
|
||||
|
||||
public long messagesWrote() {
|
||||
return m_messageWrote;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
package io.moquette.server.netty.metrics;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Collects all the metrics from the various pipeline.
|
||||
*/
|
||||
public class MessageMetricsCollector {
|
||||
|
||||
private AtomicLong readMsgs = new AtomicLong();
|
||||
private AtomicLong wroteMsgs = new AtomicLong();
|
||||
|
||||
public MessageMetrics computeMetrics() {
|
||||
MessageMetrics allMetrics = new MessageMetrics();
|
||||
allMetrics.incrementRead(readMsgs.get());
|
||||
allMetrics.incrementWrote(wroteMsgs.get());
|
||||
return allMetrics;
|
||||
}
|
||||
|
||||
public void sumReadMessages(long count) {
|
||||
readMsgs.getAndAdd(count);
|
||||
}
|
||||
|
||||
public void sumWroteMessages(long count) {
|
||||
wroteMsgs.getAndAdd(count);
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
|
||||
package io.moquette.server.netty.metrics;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.util.Attribute;
|
||||
import io.netty.util.AttributeKey;
|
||||
|
||||
import static io.netty.channel.ChannelFutureListener.CLOSE_ON_FAILURE;
|
||||
|
||||
public class MessageMetricsHandler extends ChannelDuplexHandler {
|
||||
|
||||
private static final AttributeKey<MessageMetrics> ATTR_KEY_METRICS = AttributeKey.valueOf("MessageMetrics");
|
||||
|
||||
private MessageMetricsCollector m_collector;
|
||||
|
||||
public MessageMetricsHandler(MessageMetricsCollector collector) {
|
||||
m_collector = collector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
Attribute<MessageMetrics> attr = ctx.channel().attr(ATTR_KEY_METRICS);
|
||||
attr.set(new MessageMetrics());
|
||||
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
MessageMetrics metrics = ctx.channel().attr(ATTR_KEY_METRICS).get();
|
||||
metrics.incrementRead(1);
|
||||
ctx.fireChannelRead(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
MessageMetrics metrics = ctx.channel().attr(ATTR_KEY_METRICS).get();
|
||||
metrics.incrementWrote(1);
|
||||
ctx.write(msg, promise).addListener(CLOSE_ON_FAILURE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
|
||||
MessageMetrics metrics = ctx.channel().attr(ATTR_KEY_METRICS).get();
|
||||
m_collector.sumReadMessages(metrics.messagesRead());
|
||||
m_collector.sumWroteMessages(metrics.messagesWrote());
|
||||
super.close(ctx, promise);
|
||||
}
|
||||
|
||||
public static MessageMetrics getMessageMetrics(Channel channel) {
|
||||
return channel.attr(ATTR_KEY_METRICS).get();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user