Smack4.1.6+版本不确定是否可用(未实践,理论上应该没有问题),因Smack4.2.0版本改动较大
下载请前往https://download.csdn.net/download/w690333243/10352948
思路:参考Smack源码中SLF4JSmackDebugger
注:文章中所有 Log.debug的地方,均需要换成你自己的输出到文件的打印方式
在XMPPTCPConnectionConfiguration 配置configBuilder处(设置服务器地址,域名处)添加如下代码
configBuilder.setDebuggerEnabled(true);//开启Smack xmpp报文打印log
//SmackConfiguration.DEBUG = true;//暂时还不知道这是干嘛用的,之前看到有篇文章数,版本发布时要把SmackConfiguration.DEBUG 去掉,刚开始置位true是为了调试,小编没加这行代码,报文可以正常打印
SmackConfiguration.setDebuggerFactory(new XmppDebuggerFactory());//使用自己的log输出
一、XmppDebugger.java
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.ReconnectionManager;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.debugger.SmackDebugger;
import org.jivesoftware.smack.util.ObservableReader;
import org.jivesoftware.smack.util.ObservableWriter;
import org.jxmpp.util.XmppStringUtils;
import java.io.Reader;
import java.io.Writer;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Description:此类用于打印xmpp协议收发包信息
*/
public class XmppDebugger implements SmackDebugger
{
public static final String LOGGER_NAME = "XMPP_SMACK";
public static final AtomicBoolean printInterpreted = new AtomicBoolean(true);
public static final String SENT_TAG = "SENT";
public static final String RECEIVED_TAG = "RECV";
private final XMPPConnection connection;
private final StanzaListener receivedListener = new XmppLoggingPacketListener(RECEIVED_TAG);
private final StanzaListener sentListener = new XmppLoggingPacketListener(SENT_TAG);
private final XmppRawXmlListener XmppRawXmlListener = new XmppRawXmlListener();
private ObservableWriter writer;
private ObservableReader reader;
/**
* Makes Smack use this Debugger
*/
public static void enable()
{
SmackConfiguration.setDebuggerFactory(new XmppDebuggerFactory());
}
/**
* Create new Xmpp Smack Debugger instance
*
* @param connection
* Smack connection to debug
* @param writer
* connection data writer to observe
* @param reader
* connection data reader to observe
*/
public XmppDebugger(XMPPConnection connection, Writer writer, Reader reader)
{
this.connection = connection;
this.writer = new ObservableWriter(writer);
this.writer.addWriterListener(XmppRawXmlListener);
this.reader = new ObservableReader(Validate.notNull(reader));
this.reader.addReaderListener(XmppRawXmlListener);
this.connection.addConnectionListener(new XmppLoggingConnectionListener(connection));
}
@Override
public Reader newConnectionReader(Reader newReader)
{
reader.removeReaderListener(XmppRawXmlListener);
reader = new ObservableReader(newReader);
reader.addReaderListener(XmppRawXmlListener);
return reader;
}
@Override
public Writer newConnectionWriter(Writer newWriter)
{
writer.removeWriterListener(XmppRawXmlListener);
writer = new ObservableWriter(newWriter);
writer.addWriterListener(XmppRawXmlListener);
return writer;
}
@Override
public void userHasLogged(String user)
{
String userTitle = getUserTitle(user);
Log.debug(XmppDebugger.LOGGER_NAME, "userHasLogged User logged in connection.hashCode()=" + connection.hashCode() + " userTitle=" + userTitle);
}
private String getUserTitle(String user)
{
if (("@" + connection.getServiceName()).equals(XmppStringUtils.parseBareJid(user)))
{
return "<Anonymous>@" + connection.getServiceName();
}
else
{
return user;
}
}
@Override
public Reader getReader()
{
return reader;
}
@Override
public Writer getWriter()
{
return writer;
}
@Override
public StanzaListener getReaderListener()
{
return receivedListener;
}
@Override
public StanzaListener getWriterListener()
{
return sentListener;
}
}
二、Validate.java
/**
* Description:此类用于
*/
/**
* This is package-level helper class to validate dependencies while initialization is in progress
*/
final class Validate
{
private Validate()
{ /* do not create instances */ }
public static <T> T notNull(T instance)
{
return notNull(instance, null);
}
public static <T> T notNull(T instance, String message)
{
if (instance == null)
{
throw new NullPointerException(message);
}
else
{
return instance;
}
}
}
三、XmppDebuggerFactory.java
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.debugger.SmackDebugger;
import org.jivesoftware.smack.debugger.SmackDebuggerFactory;
import java.io.Reader;
import java.io.Writer;
/**
* Description:此类用于打印xmpp协议收发包信息
*/
public class XmppDebuggerFactory implements SmackDebuggerFactory
{
@Override
public SmackDebugger create(XMPPConnection connection, Writer writer, Reader reader) throws IllegalArgumentException {
return new XmppDebugger(connection, writer, reader);
}
}
四、XmppLoggingPacketListener.java
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.packet.Stanza;
/**
* Description:此类用于打印xmpp协议收发包信息
*/
public class XmppLoggingPacketListener implements StanzaListener
{
private final String prefix;
public XmppLoggingPacketListener(String prefix)
{
this.prefix = Validate.notNull(prefix);
}
public void processPacket(Stanza packet)
{
if (XmppDebugger.printInterpreted.get())
{
Log.debug(XmppDebugger.LOGGER_NAME, prefix + " " + packet.getClass().getName() + " " + packet.toXML());
}
}
}
五、XmppRawXmlListener.java
import org.jivesoftware.smack.util.ReaderListener;
import org.jivesoftware.smack.util.WriterListener;
import java.util.logging.Logger;
/**
* Description:此类用于打印xmpp协议收发包信息
*/
public class XmppRawXmlListener implements ReaderListener, WriterListener
{
XmppRawXmlListener()
{
}
@Override
public void read(String str)
{
Log.debug(XmppDebugger.LOGGER_NAME, XmppDebugger.RECEIVED_TAG + ": " + str);
}
@Override
public void write(String str)
{
Log.debug(XmppDebugger.LOGGER_NAME, XmppDebugger.SENT_TAG + ": " + str);
}
}
六、XmppLoggingConnectionListener.java
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.XMPPConnection;
/**
* Description:此类用于打印xmpp协议收发包信息
*/
public class XmppLoggingConnectionListener implements ConnectionListener
{
private final XMPPConnection connection;
public XmppLoggingConnectionListener(XMPPConnection connection)
{
this.connection = Validate.notNull(connection);
}
@Override
public void connected(XMPPConnection connection)
{
Log.debug(XmppDebugger.LOGGER_NAME, "Connection connected: " + connection.hashCode());
}
@Override
public void authenticated(XMPPConnection connection, boolean resumed)
{
Log.debug(XmppDebugger.LOGGER_NAME, "authenticated connection.getUser()=" + connection.getUser());
}
public void connectionClosed()
{
Log.debug(XmppDebugger.LOGGER_NAME, "connectionClosed");
}
public void connectionClosedOnError(Exception e)
{
Log.debug(XmppDebugger.LOGGER_NAME, "connectionClosedOnError e=" + e);
}
public void reconnectionFailed(Exception e)
{
Log.debug(XmppDebugger.LOGGER_NAME, "reconnectionFailed e=" + e);
}
public void reconnectionSuccessful()
{
Log.debug(XmppDebugger.LOGGER_NAME, "reconnectionSuccessful ");
}
public void reconnectingIn(int seconds)
{
Log.debug(XmppDebugger.LOGGER_NAME, "reconnectingIn " + seconds);
}
}