从日志文件中解析JSON对象

4

我希望能够解析日志文件中的JSON对象。但是,使用JSON解析器需要我的完整文件都是JSON格式,而这并不是我的情况。有没有办法可以逐行解析文件并获取JSON对象呢? 以下是我的日志文件格式:

2015-10-19 11:24:35:701 INFO  BrokerTcpClient:28 - Set destination 
2015-10-19 11:24:35:929 DEBUG BrokerTcpClient:32 - received data: {type=data,  payload={

    "core" : [ {
      "id" : {
        "datatype" : "http://www.w3.org/2001/hk#long",
        "type" : "gh",
        "value" : "gh"
      },
      "entity" : {
        "type" : "uri",
        "value" : "http://fg.fg.com/ext/g/fg"
      },
      "Sno" : {
        "type" : "literal",
        "value" : "fg"
      }]
2015-10-19 11:24:35:701 INFO  BrokerTcpClient:28 - Set destination 
2015-10-19 11:24:35:929 DEBUG BrokerTcpClient:32
    "core" : [ {
      "id" : {
        "datatype" : "http://www.w3.org/2001/hk#long",
        "type" : "gh",
        "value" : "gh"
      },
      "entity" : {
        "type" : "uri",
        "value" : "http://fg.fg.com/ext/g/fg"
      },
      "Sno" : {
        "type" : "literal",
        "value" : "fg"
      }]

请问有谁能帮我获取我的JSON对象。当我尝试解析一行JSON对象时,会抛出异常。


日志有特定的格式,所以你只需要去掉你不关心的部分:YYYY-MM-DD HH:MM:SS:mmm <事件级别> <对象>:<行号> - Mike
抱歉,我没有听懂你的意思。我的理解是逐行读取数据,然后在哪里找到我的数据以将其存储在任何集合中?如果我错了,请指导我。 - user23385
即使剥离时间戳日志数据,你示例中的json也是无效的。在第一个“json”中,你有1个未关闭的{,因此你不仅需要解析尝试的json,还需要关闭未关闭的{或[。 - vbranden
你可以遍历每一行,如果当前行不以时间戳开头而上一行是,则假设当前行是 JSON 对象的一部分,并继续将行添加到对象字符串中,直到遇到另一个时间戳为止,然后用 {} 将该对象包装起来,使其成为有效的 JSON。 - vbranden
抱歉,那是我的复制粘贴错误。JSON对象在日志文件中也可以使用完整的结束括号进行验证。因此,我应该将一个JSON对象添加到一个字符串对象中,并使用JSON解析器进行解析。我会尝试这样做。但是我的日志文件非常大,所以我一直避免使用这种方法。 - user23385
2个回答

0

这里有一个适用于发布的示例日志的解决方案。

import java.io.*;
import com.fasterxml.jackson.databind.*;
public class JSONTest {
    public static void main(String[] args) {
        String logFilename = "C://Temp/sample.log";
        String line, json = "";

        try (BufferedReader br = new BufferedReader(new FileReader(logFilename))) {
            while ((line = br.readLine()) != null) {
                if (isLogLine(line)) {
                    if (!json.isEmpty()) {
                        parseJson(json);
                        json = "";
                    }
                } else {
                    json += line;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static boolean isLogLine(String line) {
        return line.matches("^\\d{4}\\-\\d{2}\\-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}:\\d{3}.+$");
    }

    public static void parseJson(String json) throws Exception {
        if (!json.startsWith("{") && !json.endsWith("}")) json = "{" + json + "}";
        ObjectMapper om = new ObjectMapper();
        System.out.println(om.readValue(fixJson(json), Object.class));
    }

    public static String fixJson(String json) {
        return "{" + json.replace("}]", "}}]") + "}";
    }
}

注意事项:

  1. 用于识别日志行的正则表达式检查行开头的时间戳。如果日志消息跨越多行(例如,如果消息包含换行符),则无法正常工作。
  2. 有一种方法尝试“修复”日志文件中不完整的JSON,如果沿途还有更多不完整的JSON情况,则可能需要额外的逻辑。
  3. 我使用了Jackson Json解析器,并让ObjectMapper确定要解析成什么数据结构。

我尝试过了。能够将日志文件中的JSON对象分离成字符串,但是当我尝试使用JSONParser解析它时,会出现异常:"在第8个标记处发现意外的令牌"。为什么会这样呢?我不明白这是否不是JSON的正确格式。请帮忙解决。 - user23385
这就是为什么我特意创建了 fixJson() 方法,以便在解析之前可以“玩弄”字符串并修复它。完整的异常消息包括 JSON 输入,因此您可以看到第8个字符出了什么问题。如果您发布完整的异常消息,我可以提供帮助。 - Sharon Ben Asher

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接