java util记录多个处理程序导致重复日志消息
我遇到的情况是,多个处理程序被设置到一个记录器中。每个处理程序都会替换记录的敏感信息 请参阅下面的SSCCEjava util记录多个处理程序导致重复日志消息,java,java.util.logging,Java,Java.util.logging,我遇到的情况是,多个处理程序被设置到一个记录器中。每个处理程序都会替换记录的敏感信息 请参阅下面的SSCCE import java.util.logging.ConsoleHandler; import java.util.logging.Formatter; import java.util.logging.LogRecord; import java.util.logging.Logger; public class TestLogging { public static v
import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
public class TestLogging {
public static void main(String[] args) {
Logger logger=Logger.getLogger(A.class.getName());
logger.addHandler(new ConsoleHandler(){
{
setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return record.getMessage().replaceAll("method","replacing method");
}
});
}
});
logger.addHandler(new ConsoleHandler(){
{
setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return record.getMessage().replaceAll("Logging","replacing logging");
}
});
}
});
logger.setUseParentHandlers(false);
A a =new A();
a.method();
}
public static class A{
private static final Logger LOGGER=Logger.getLogger(A.class.getName());
public void method(){
LOGGER.info("\nLogging from inside method");
}
}
}
我希望输出是“从替换方法内部替换日志记录”,但我得到的是这样的输出
Logging from inside replacing method
replacing logging from inside method
如果我发现已经设置了另一个处理程序,如何将这两个处理程序合并为一个处理程序?按设计,处理程序不应链接或合并,因为它们的主要目的是执行最终的日志记录处理,如写入文件。我建议稍微改变一下方法,合并格式化程序而不是处理程序。请看以下示例:
public class TestLogging {
public static void main(String[] args) {
Logger logger = Logger.getLogger(A.class.getName());
FormatHandler handler = new FormatHandler();
logger.addHandler(handler);
handler.addFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return record.getMessage().replaceAll("method", "replacing method");
}
});
handler.addFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return record.getMessage().replaceAll("Logging", "replacing logging");
}
});
logger.setUseParentHandlers(false);
A a = new A();
a.method();
}
public static class FormatHandler extends ConsoleHandler {
private List<Formatter> formatters = new ArrayList<>();
public FormatHandler() {
setFormatter(new CompositeFormatter());
}
public void addFormatter(Formatter f) {
formatters.add(f);
}
class CompositeFormatter extends Formatter {
@Override
public synchronized String format(LogRecord record) {
String modifiedMessage;
for(Formatter formatter : formatters){
modifiedMessage = formatter.format(record);
record.setMessage(modifiedMessage);
}
return record.getMessage();
}
}
}
public static class A {
private static final Logger LOGGER = Logger.getLogger(A.class.getName());
public void method() {
LOGGER.info("\nLogging from inside method");
}
}
}
公共类测试日志{
公共静态void main(字符串[]args){
Logger=Logger.getLogger(A.class.getName());
FormatHandler=新的FormatHandler();
addHandler(handler);
handler.addFormatter(新格式化程序(){
@凌驾
公共字符串格式(日志记录){
return record.getMessage().replaceAll(“方法”,“替换方法”);
}
});
handler.addFormatter(新格式化程序(){
@凌驾
公共字符串格式(日志记录){
return record.getMessage().replaceAll(“记录”,“替换记录”);
}
});
logger.setUseParentHandlers(false);
A=新的A();
a、 方法();
}
公共静态类FormatHandler扩展了ConsoleHandler{
私有列表格式化程序=新的ArrayList();
公共格式化处理程序(){
setFormatter(新的CompositeFormatter());
}
公共void addFormatter(格式化程序f){
格式化程序。添加(f);
}
类复合格式化程序扩展格式化程序{
@凌驾
公共同步字符串格式(日志记录){
字符串修改消息;
for(格式化程序格式化程序:格式化程序){
modifiedMessage=formatter.format(记录);
record.setMessage(modifiedMessage);
}
return record.getMessage();
}
}
}
公共静态A类{
私有静态最终记录器Logger=Logger.getLogger(A.class.getName());
公开作废法(){
LOGGER.info(“\n从内部登录方法”);
}
}
}
它执行您想要的输出。按设计处理程序不应该被链接或合并,因为它们的主要目的是执行最终的日志记录处理,如写入文件。我建议稍微改变一下方法,合并格式化程序而不是处理程序。请看以下示例:
public class TestLogging {
public static void main(String[] args) {
Logger logger = Logger.getLogger(A.class.getName());
FormatHandler handler = new FormatHandler();
logger.addHandler(handler);
handler.addFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return record.getMessage().replaceAll("method", "replacing method");
}
});
handler.addFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return record.getMessage().replaceAll("Logging", "replacing logging");
}
});
logger.setUseParentHandlers(false);
A a = new A();
a.method();
}
public static class FormatHandler extends ConsoleHandler {
private List<Formatter> formatters = new ArrayList<>();
public FormatHandler() {
setFormatter(new CompositeFormatter());
}
public void addFormatter(Formatter f) {
formatters.add(f);
}
class CompositeFormatter extends Formatter {
@Override
public synchronized String format(LogRecord record) {
String modifiedMessage;
for(Formatter formatter : formatters){
modifiedMessage = formatter.format(record);
record.setMessage(modifiedMessage);
}
return record.getMessage();
}
}
}
public static class A {
private static final Logger LOGGER = Logger.getLogger(A.class.getName());
public void method() {
LOGGER.info("\nLogging from inside method");
}
}
}
公共类测试日志{
公共静态void main(字符串[]args){
Logger=Logger.getLogger(A.class.getName());
FormatHandler=新的FormatHandler();
addHandler(handler);
handler.addFormatter(新格式化程序(){
@凌驾
公共字符串格式(日志记录){
return record.getMessage().replaceAll(“方法”,“替换方法”);
}
});
handler.addFormatter(新格式化程序(){
@凌驾
公共字符串格式(日志记录){
return record.getMessage().replaceAll(“记录”,“替换记录”);
}
});
logger.setUseParentHandlers(false);
A=新的A();
a、 方法();
}
公共静态类FormatHandler扩展了ConsoleHandler{
私有列表格式化程序=新的ArrayList();
公共格式化处理程序(){
setFormatter(新的CompositeFormatter());
}
公共void addFormatter(格式化程序f){
格式化程序。添加(f);
}
类复合格式化程序扩展格式化程序{
@凌驾
公共同步字符串格式(日志记录){
字符串修改消息;
for(格式化程序格式化程序:格式化程序){
modifiedMessage=formatter.format(记录);
record.setMessage(modifiedMessage);
}
return record.getMessage();
}
}
}
公共静态A类{
私有静态最终记录器Logger=Logger.getLogger(A.class.getName());
公开作废法(){
LOGGER.info(“\n从内部登录方法”);
}
}
}
它执行您想要的输出。不确定为什么投票关闭它。有礼貌地说为什么这需要关闭,甚至是在投票否决一个问题时。不知道为什么这被投票否决。有礼貌地说,为什么需要关闭这个问题,甚至在投票否决一个问题时。谢谢!。。现在将更改我的设计…)嘿不过我有个问题。。我们不能将控制台句柄和文件句柄添加到记录器并格式化消息吗?。。我已经被handler替换为FileHandler,它将在生产系统中使用。但是我想把它记录到我的开发人员机器上的控制台上(为什么不呢?)只要把CompositeFormatter也添加到FileHandler中就行了。然后回到同一个问题上,在控制台中同样的消息被记录了两次,我看到了。如果您想在开发和生产环境中使用不同的记录器实现,那么引入某种“开发模式”标志或构建概要文件。否则你的应用程序将永远不会知道它运行在哪种环境中。谢谢!。。现在将更改我的设计…)嘿不过我有个问题。。我们不能将控制台句柄和文件句柄添加到记录器并格式化消息吗?。。我已经被handler替换为FileHandler,它将在生产系统中使用。但是我想把它记录到我的开发人员机器上的控制台上(为什么不呢?)只要把CompositeFormatter也添加到FileHandler中就行了。然后回到同一个问题上,在控制台中同样的消息被记录了两次,我看到了。如果您想在开发和生产环境中使用不同的记录器实现,那么引入某种“开发模式”标志或构建概要文件。否则,你的应用程序永远不会知道它运行在哪种环境中