技术点
- 自定义Appender:Logback允许通过继承
AppenderBase
类来创建自定义的Appender,用于将日志发送到远程服务器。
- 加密处理:使用Java的加密库(如JCE,Java Cryptography Architecture)对日志内容进行加密。
- 网络通信:利用Java的网络编程技术(如Socket、HTTP Client)将加密后的日志发送到远程服务器。
- SLF4J绑定:确保自定义的Logback Appender能与SLF4J正确绑定,使项目中的日志调用能使用到新的功能。
实现步骤
- 创建自定义Appender类
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
public class CustomEncryptedAppender extends AppenderBase<ILoggingEvent> {
@Override
protected void append(ILoggingEvent eventObject) {
// 这里开始处理日志
}
}
- 加密日志内容
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
public class EncryptionUtil {
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
public static byte[] encrypt(String data, SecretKey secretKey) throws Exception {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
}
public static SecretKey generateSecretKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
keyGenerator.init(128, new SecureRandom());
return keyGenerator.generateKey();
}
}
- 发送加密日志到远程服务器
import java.io.OutputStream;
import java.net.Socket;
public class RemoteSender {
public static void send(byte[] encryptedData, String serverAddress, int port) throws Exception {
try (Socket socket = new Socket(serverAddress, port)) {
OutputStream outputStream = socket.getOutputStream();
outputStream.write(encryptedData);
}
}
}
- 使用HTTP Client(以Apache HttpClient为例)
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class HttpRemoteSender {
public static void send(byte[] encryptedData, String serverUrl) throws Exception {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(serverUrl);
HttpEntity entity = new ByteArrayEntity(encryptedData);
httpPost.setEntity(entity);
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
EntityUtils.consume(response.getEntity());
}
}
}
}
- 在自定义Appender中整合加密与发送逻辑
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CustomEncryptedAppender extends AppenderBase<ILoggingEvent> {
private static final ExecutorService executorService = Executors.newSingleThreadExecutor();
private String serverAddress;
private int port;
private String serverUrl; // 如果使用HTTP
public void setServerAddress(String serverAddress) {
this.serverAddress = serverAddress;
}
public void setPort(int port) {
this.port = port;
}
public void setServerUrl(String serverUrl) {
this.serverUrl = serverUrl;
}
@Override
protected void append(ILoggingEvent eventObject) {
executorService.submit(() -> {
try {
String logMessage = eventObject.getFormattedMessage();
SecretKey secretKey = EncryptionUtil.generateSecretKey();
byte[] encryptedData = EncryptionUtil.encrypt(logMessage, secretKey);
if (serverUrl != null) {
HttpRemoteSender.send(encryptedData, serverUrl);
} else {
RemoteSender.send(encryptedData, serverAddress, port);
}
} catch (Exception e) {
addError("Failed to send encrypted log", e);
}
});
}
}
- 配置Logback
在
logback.xml
中添加自定义Appender的配置:
<configuration>
<appender name="CUSTOM_ENCRYPTED" class="com.example.CustomEncryptedAppender">
<serverAddress>your_server_address</serverAddress>
<port>your_port</port>
<!-- 如果使用HTTP -->
<serverUrl>your_http_server_url</serverUrl>
</appender>
<root level="info">
<appender-ref ref="CUSTOM_ENCRYPTED" />
</root>
</configuration>
- 确保SLF4J绑定
项目中已经使用SLF4J结合Logback,只要自定义的Logback Appender配置正确,SLF4J就能自动绑定并使用新的Appender来处理日志。例如,项目中的日志调用方式不变:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SomeClass {
private static final Logger logger = LoggerFactory.getLogger(SomeClass.class);
public void someMethod() {
logger.info("This is a log message");
}
}