我对如何在Java EE OSGi环境中正确设置记录器感到非常困惑。 以下是我的要求:
- 每个 EBA 仅 1 个日志文件(捆绑包分组)
- 每个应用程序服务器多个日志文件(由于多个 EBA)
- 不想执行类加载器魔术(如果我使用的库这样做很好,我只是不想写它)
- 必须在一天结束时轮换日志文件,并且一次只维护 7 个日志文件
- 最好不需要为每个 EBA 创建日志记录捆绑包。 如果我告诉其他开发人员为每个应用程序编写自己的日志记录互操作,则不会购买。
- 必须与 WebSphere Application Server 8.5.5 配合使用
首先,我尝试像其他Java EE应用程序一样在log4j之上使用SLF4j,但是没有任何东西可以找到我的log4j.properties。 我尝试了导入 SLF4j 的变体,并且也遇到了将其加载到 1 个捆绑包中会阻止它在另一个捆绑包中加载的问题。
接下来,我查看了 PAX 记录器,但它似乎是全局记录,而不是每个 EBA。
尝试使用 OSGi LogService 会阻止我的捆绑包部署到 WebSphere,而且我不确定如何才能让它满足我的需求。
我可以看到的唯一选择是编写我自己的捆绑包,该捆绑包保留了捆绑包 -> 日志文件的注册表(在客户端类上使用 FrameworkUtil.getBundle)并在其中实现完整的日志记录框架。 如果它有类加载器隔离问题,那么可能会推送到 EJB 来执行实际的日志记录。 我真的希望这不是我唯一的解决方案。
任何人都可以指出一些可以帮助我的文档吗?
谢谢!
人们普遍对日志服务感到困惑......日志服务不存储任何日志,它只是充当调度程序。我理解这种混乱,因为日志服务被强制要求在初始启动时有一个小缓冲区,并提供一个 API 来获取缓冲区。
对于所需的内容,应使用日志读取器服务添加日志侦听器。使用声明式服务,您想要的非常容易。这是一个实现您的要求的组件:
@Component(provide = {}, immediate = true) public class Logger extends Thread
implements LogListener {
final BlockingQueue<LogEntry> queue = new ArrayBlockingQueue<LogEntry>(1000);
File root;
@Reference void setLR(LogReaderService lr) {
lr.addLogListener(this);
}
@Activate void activate(BundleContext context, Map<String,Object> props) {
if ( props.containsKey("root"))
root = new File((String) props.get("root"));
else
root = context.getDataFile("logs");
root.mkdirs();
start();
}
@Deactivate void deactivate() {
interrupt();
}
@Override public void logged(LogEntry entry) {
queue.offer(entry); // ignore full silently
}
public void run() {
while (true)
try {
LogEntry entry = queue.take();
File file = getPath(entry);
if (file.isFile()) {
long days = TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis()
- file.lastModified());
if (days > 2) file.delete();
}
try (OutputStream raf = new FileOutputStream(file, true)) {
String s = String.format("%tT [%03d] %s%n", entry.getTime(), entry
.getBundle().getBundleId(), entry.getMessage());
raf.write(s.getBytes("UTF-8"));
}
} catch (InterruptedException ie) {
return;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private File getPath(LogEntry entry) {
long rollover = TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis()) % 7;
String eba = "eba"; // fill in eba from entry.getBundle()?
return new File(root, "log-" + eba + "-" + rollover + ".msg");
}
}
这当然可以更有效率一点,但这只剩下练习了。