簡體   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