繁体   English   中英

记录对 Java servlet 的访问

[英]Logging access to Java servlet

我目前正在使用 Servlet 开发 Java Web 应用程序。 我需要做的是每次访问该网站时都将其记录到一个文件中。 为此,我使用了过滤器。 到目前为止,我已经达到了可以将所有内容打印到控制台的程度。

我现在需要做的是将它存储到一个最多 10.000 个条目的文件中,最长可达 30 天(如果达到最大条目数,则在写入新条目时替换最旧的条目)。

我怎样才能做到这一点?

PS:我不能在这个作业中使用数据库

编辑:我没有使用网络框架。 我可以使用日志框架。

所以,这个问题实际上促使我调查是否有任何流行的日志框架实际上可以按要求完成任务。

虽然大多数都根据文件大小和日期/时间来滚动日志,但他们都没有一种简单的方法可以根据日志文件中的条目来滚动日志。 此外,现有的日志框架通常将每一天(有时是更小的时间单位)存储在它们自己的单独文件中,从而根据日期/时间进行有效的清理。

由于需要单个文件中的最大行数,这需要将整个文件读入内存(非常低效!)。 当过去和现在的所有内容都被写入单个文件时,删除旧条目需要解析每行的写入日期/时间(同样,效率低下!)。

下面是一个简单的程序来证明可以做到这一点,但是这种方法存在一些严重的问题:

  • 不是线程安全的(如果两个线程尝试同时读/写一个条目,一个将被破坏并且消息将被跳过)
  • 啜饮很糟糕(一万个条目很多:服务器可以将所有这些都啜饮到内存中吗?)

这可能适用于玩具项目、演示或学校作业。

这不适合生产应用程序,或者网络上任何一个多人同时使用的东西。


简而言之,如果您尝试将在 Internet 上找到的手工程序用于其他人依赖的关键任务应用程序,那么您将得到您应得的。


public static void main(final String[] args) throws Exception
{
    final File logFile = new File("C:/", "EverythingInOneBigGiant.log");
    final int maxDays = 30;
    final int maxEntries = 10000;

    while (true)
    {
        // Just log the current time for this example, also makes parsing real simple
        final String msg = Instant.now().toString();
        slurpAndParse(logFile, msg, maxDays, maxEntries);

        // Wait a moment, before writing another entry
        Thread.sleep(750);
    }
}

private static void slurpAndParse(final File f, final String msg, final int maxDays, final int maxEntries)
        throws Exception
{
    // Slurp entire file into this buffer (possibly very large!)
    // Could crash your server if you run out of memory
    final StringBuffer sb = new StringBuffer();

    if (f.exists() && f.isFile())
    {
        final LocalDateTime now = LocalDateTime.now();

        final long totalLineCount = Files.lines(Paths.get(f.getAbsolutePath())).count();
        final long startAtLine = (totalLineCount < maxEntries ? 0 : (totalLineCount - maxEntries) + 1);
        long currentLineCount = 0;

        try (final BufferedReader br = new BufferedReader(new FileReader(f)))
        {
            String line;
            while (null != (line = br.readLine()))
            {
                // Ignore all lines before the start counter
                if (currentLineCount < startAtLine)
                {
                    ++currentLineCount;
                    continue;
                }

                // Parsing log data... while writing to the same log... ugh... how hideous
                final LocalDateTime lineDate = LocalDateTime.parse(line, DateTimeFormatter.ISO_ZONED_DATE_TIME);
                final Duration timeBetween = Duration.between(lineDate, now);
                // ... or maybe just use Math.abs() here? I defer to the date/time buffs
                final long dayDiff = (timeBetween.isNegative() ? timeBetween.negated() : timeBetween).toDays();

                // Only accept lines less than the max age in days
                if (dayDiff <= maxDays)
                {
                    sb.append(line);
                    sb.append(System.lineSeparator());
                }
            }
        }
    }

    System.out.println(msg);

    // Add the new log entry
    sb.append(msg);
    sb.append(System.lineSeparator());

    writeLog(f, sb.toString());
}

private static void writeLog(final File f, final String content) throws IOException
{
    try (final Writer out = new FileWriter(f))
    {
        out.write(content);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM