读取大量日志文件并 post 到 Java 中的 API 端点的最有效方法是什么?
What's the most efficient way to read in a massive log file, and post to an API endpoint in Java?
目前我的应用程序中有大量日志文件,我需要 post 到端点。我定期 运行 一个将整个文件读入列表的方法,执行一些格式化以便端点接受它,然后使用 StringBuilder 转换字符串,return 这个字符串,然后 post 它到我的端点。哦,我忘了说,我将数据分成 X 个字符的块。我在我的应用程序中发现了一些内存问题,我正在尝试解决这个问题。
这就是我将数据划分到临时列表的方式
if (logFile.exists()) {
try (BufferedReader br = new BufferedReader(new FileReader(logFile.getPath()))) {
String line;
while ((line = br.readLine()) != null) {
if (isJSONValid(line)) {
temp.add(line);
tempCharCount += line.length();
}
if (tempCharCount >= LOG_PARTITION_CHAR_COUNT) {
// Formatting for the backend
String tempString = postFormat(temp);
// Send
sendLogs(tempString);
// Refresh
temp = new ArrayList<>();
tempCharCount = 0;
}
}
// Send "dangling" data
// Formatting for the backend
String tempString = postFormat(temp);
// Send
sendLogs(tempString);
} catch (FileNotFoundException e) {
Timber.e(new Exception(e));
} catch (IOException e) {
Timber.e(new Exception(e));
}
所以当我们达到字符数的分区限制时,您可以看到我们正在 运行ning
String tempString = postFormat(temp);
这是我们确保我们的数据被格式化为端点将接受的 json 数据字符串的地方。
private String postFormat(ArrayList<String> list) {
list.add(0, LOG_ARRAY_START);
list.add(LOG_ARRAY_END);
StringBuilder sb = new StringBuilder();
for (int stringCount = 0; stringCount < list.size(); stringCount++) {
sb.append(list.get(stringCount));
// Only add comma separators after initial element, but never add to final element and
// its preceding element to match the expected backend input
if (stringCount > 0 && stringCount < list.size() - 2) {
sb.append(",");
}
}
return sb.toString();
}
正如您想象的那样,如果您有一个很大的日志文件,并且这些请求是异步发出的,那么我们将使用大量内存。一旦我们的 Stringbuilder 完成,我们 return 作为一个字符串,最终将被 gzip 压缩并 posted 到一个端点。
我正在寻找减少内存使用的方法。我对它进行了一些侧面的分析,可以看出它的效率有多低,但我不确定如何才能做得更好。任何想法表示赞赏。
我有一个建议给你。
临时文件中的格式化输出 - 您可以在临时文件中写入格式化输出。一旦转换完成,您就可以读取临时文件并发送到端点。如果你不关心顺序,那么你可以使用多线程来追加同一个文件。
使用这种方法,您不会在转换时在内存中存储任何数据,这将节省大量内存。
目前我的应用程序中有大量日志文件,我需要 post 到端点。我定期 运行 一个将整个文件读入列表的方法,执行一些格式化以便端点接受它,然后使用 StringBuilder 转换字符串,return 这个字符串,然后 post 它到我的端点。哦,我忘了说,我将数据分成 X 个字符的块。我在我的应用程序中发现了一些内存问题,我正在尝试解决这个问题。
这就是我将数据划分到临时列表的方式
if (logFile.exists()) {
try (BufferedReader br = new BufferedReader(new FileReader(logFile.getPath()))) {
String line;
while ((line = br.readLine()) != null) {
if (isJSONValid(line)) {
temp.add(line);
tempCharCount += line.length();
}
if (tempCharCount >= LOG_PARTITION_CHAR_COUNT) {
// Formatting for the backend
String tempString = postFormat(temp);
// Send
sendLogs(tempString);
// Refresh
temp = new ArrayList<>();
tempCharCount = 0;
}
}
// Send "dangling" data
// Formatting for the backend
String tempString = postFormat(temp);
// Send
sendLogs(tempString);
} catch (FileNotFoundException e) {
Timber.e(new Exception(e));
} catch (IOException e) {
Timber.e(new Exception(e));
}
所以当我们达到字符数的分区限制时,您可以看到我们正在 运行ning
String tempString = postFormat(temp);
这是我们确保我们的数据被格式化为端点将接受的 json 数据字符串的地方。
private String postFormat(ArrayList<String> list) {
list.add(0, LOG_ARRAY_START);
list.add(LOG_ARRAY_END);
StringBuilder sb = new StringBuilder();
for (int stringCount = 0; stringCount < list.size(); stringCount++) {
sb.append(list.get(stringCount));
// Only add comma separators after initial element, but never add to final element and
// its preceding element to match the expected backend input
if (stringCount > 0 && stringCount < list.size() - 2) {
sb.append(",");
}
}
return sb.toString();
}
正如您想象的那样,如果您有一个很大的日志文件,并且这些请求是异步发出的,那么我们将使用大量内存。一旦我们的 Stringbuilder 完成,我们 return 作为一个字符串,最终将被 gzip 压缩并 posted 到一个端点。
我正在寻找减少内存使用的方法。我对它进行了一些侧面的分析,可以看出它的效率有多低,但我不确定如何才能做得更好。任何想法表示赞赏。
我有一个建议给你。
临时文件中的格式化输出 - 您可以在临时文件中写入格式化输出。一旦转换完成,您就可以读取临时文件并发送到端点。如果你不关心顺序,那么你可以使用多线程来追加同一个文件。 使用这种方法,您不会在转换时在内存中存储任何数据,这将节省大量内存。