1

我对如何在 Java EE OSGi 环境中正确设置记录器感到很困惑。以下是我的要求:

  • 每个 EBA 仅 1 个日志文件(捆绑包分组)
  • 每个应用程序服务器有多个日志文件(由于多个 EBA)
  • 不想执行 ClassLoader 魔术(如果我使用的库可以这样做,我只是不想编写它)
  • 必须在一天结束时轮换日志文件,并且一次只能维护 7 个日志文件
  • 最好不需要为每个 EBA 创建一个日志包。如果我告诉他们为每个应用程序编写自己的日志互操作,没有其他开发人员会接受。
  • 必须与 WebSphere Application Server 8.5.5 一起使用

首先,我尝试像我们的其他 Java EE 应用程序一样在 log4j 之上使用 SLF4j,但是找不到我的 log4j.properties。我尝试了导入 SLF4j 的变体,并且还遇到了将其加载到 1 个捆绑包中阻止它加载到另一个捆绑包中的问题。

接下来我查看了 PAX 记录器,但它似乎是全局记录,而不是每个 EBA。

尝试使用 OSGi LogService 会阻止我的包部署到 WebSphere,而且我不确定如何让它满足我的要求。

我现在可以看到的唯一选择是编写我自己的包,该包为包 - > 日志文件保留一个注册表(在客户端类上使用 FrameworkUtil.getBundle)并在其中实现一个完整的日志框架。如果这有类加载器隔离问题,那么可能会推送到 EJB 来进行实际的日志记录。我真的希望这不是我唯一的解决方案。

谁能指出一些可以帮助我的文档?

谢谢!

4

1 回答 1

1

人们普遍对日志服务感到困惑......日志服务不存储任何日志,它只是充当调度程序。我理解这种混乱,因为日志服务被要求在初始启动时有一个小缓冲区,并提供一个 API 来获取缓冲区。

对于您想要的,您应该使用 Log Reader 服务添加一个 Log Listener。使用声明式服务,您想要的很容易。这是一个实现您的要求的组件:

@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");
  }
}

这当然可以做得更有效率,但这留作练习。

于 2013-10-27T14:20:49.263 回答