core/unittest/reader/GetLastLineDataUnittest.cpp (1,237 lines of code) (raw):

// Copyright 2023 iLogtail Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "common/FileSystemUtil.h" #include "common/memory/SourceBuffer.h" #include "file_server/reader/LogFileReader.h" #include "unittest/Unittest.h" namespace logtail { const std::string LOG_PART = "2021-08-25T07:00:00.000000000Z stdout P "; const std::string LOG_FULL = "2021-08-25T07:00:00.000000000Z stdout F "; const std::string LOG_FULL_NOT_FOUND = "2021-08-25T07:00:00.000000000Z stdout "; const std::string LOG_ERROR = "2021-08-25T07:00:00.000000000Z stdout"; class LastMatchedContainerdTextLineUnittest : public ::testing::Test { public: static void SetUpTestCase() { logPathDir = GetProcessExecutionDir(); if (PATH_SEPARATOR[0] == logPathDir.back()) { logPathDir.resize(logPathDir.size() - 1); } logPathDir += PATH_SEPARATOR + "testDataSet" + PATH_SEPARATOR + "LogFileReaderUnittest"; gbkFile = "gbk.txt"; utf8File = "utf8.txt"; // content of utf8.txt is equivalent to gbk.txt } static void TearDownTestCase() { remove(gbkFile.c_str()); remove(utf8File.c_str()); } void SetUp() override { std::string filepath = logPathDir + PATH_SEPARATOR + utf8File; std::unique_ptr<FILE, decltype(&std::fclose)> fp(std::fopen(filepath.c_str(), "r"), &std::fclose); if (!fp.get()) { return; } std::fseek(fp.get(), 0, SEEK_END); long filesize = std::ftell(fp.get()); std::fseek(fp.get(), 0, SEEK_SET); expectedContent.reset(new char[filesize + 1]); fread(expectedContent.get(), filesize, 1, fp.get()); expectedContent[filesize] = '\0'; for (long i = filesize - 1; i >= 0; --i) { if (expectedContent[i] == '\n') { expectedContent[i] = 0; break; }; } } void TestLastContainerdTextLineMerge(); void TestLastContainerdTextLineSingleLine(); std::unique_ptr<char[]> expectedContent; FileReaderOptions readerOpts; FileTagOptions tagOpts; CollectionPipelineContext ctx; static std::string logPathDir; static std::string gbkFile; static std::string utf8File; }; UNIT_TEST_CASE(LastMatchedContainerdTextLineUnittest, TestLastContainerdTextLineSingleLine); UNIT_TEST_CASE(LastMatchedContainerdTextLineUnittest, TestLastContainerdTextLineMerge); std::string LastMatchedContainerdTextLineUnittest::logPathDir; std::string LastMatchedContainerdTextLineUnittest::gbkFile; std::string LastMatchedContainerdTextLineUnittest::utf8File; void LastMatchedContainerdTextLineUnittest::TestLastContainerdTextLineSingleLine() { { MultilineOptions multilineOpts; LogFileReader logFileReader(logPathDir, utf8File, DevInode(), std::make_pair(&readerOpts, &ctx), std::make_pair(&multilineOpts, &ctx), std::make_pair(&tagOpts, &ctx)); BaseLineParse* baseLineParsePtr = nullptr; baseLineParsePtr = logFileReader.GetParser<ContainerdTextParser>(LogFileReader::BUFFER_SIZE); logFileReader.mLineParsers.emplace_back(baseLineParsePtr); // 异常情况+有回车 { // case: PartLogFlag存在,第三个空格存在但空格后无内容 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout P \n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(false, line.fullLine); } // case: PartLogFlag存在,第三个空格不存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout P\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(false, line.fullLine); } // case: PartLogFlag不存在,第二个空格存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout \n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: 第二个空格不存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL(testLog.substr(0, size - 1), line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: 第一个空格不存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00stdout\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL(testLog.substr(0, size - 1), line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } } // 异常情况+无回车 { // case: PartLogFlag存在,第三个空格存在但空格后无内容 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout P "; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(false, line.fullLine); } // namespace logtail // case: PartLogFlag存在,第三个空格不存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout P"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(false, line.fullLine); } // case: PartLogFlag不存在,第二个空格存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout "; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: 第二个空格不存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL(testLog, line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: 第一个空格不存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00stdout"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL(testLog, line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } } // case: F + P + P { std::string testLog = LOG_FULL + "789\n" + LOG_PART + "123\n" + LOG_PART + "456"; std::string expectedLog = LOG_FULL + "789\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL("789", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(2, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: F + P + P + '\n' { std::string testLog = LOG_FULL + "789\n" + LOG_PART + "123\n" + LOG_PART + "456\n"; std::string expectedLog = LOG_FULL + "789\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL("789", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(2, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: F + P + P + F { std::string testLog = LOG_FULL + "789\n" + LOG_PART + "123\n" + LOG_PART + "456\n" + LOG_FULL + "789"; std::string expectedLog = LOG_FULL + "789\n" + LOG_PART + "123\n" + LOG_PART + "456\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL("789", line.data.to_string()); APSARA_TEST_EQUAL(int(expectedLog.size()), line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: F + P + P + F + '\n' { std::string testLog = LOG_FULL + "789\n" + LOG_PART + "123\n" + LOG_PART + "456\n" + LOG_FULL + "789\n"; std::string expectedLog = LOG_FULL + "789\n" + LOG_PART + "123\n" + LOG_PART + "456\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL("789", line.data.to_string()); APSARA_TEST_EQUAL(int(expectedLog.size()), line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // F + errorLog { std::string testLog = LOG_FULL + "456\n" + LOG_ERROR + "789"; std::string expectedLog = LOG_FULL + "456\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL(LOG_ERROR + "789", line.data.to_string()); APSARA_TEST_EQUAL(int(expectedLog.size()), line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // F + errorLog + '\n' { std::string testLog = LOG_FULL + "456\n" + LOG_ERROR + "789\n"; std::string expectedLog = LOG_FULL + "456\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL(LOG_ERROR + "789", line.data.to_string()); APSARA_TEST_EQUAL(int(expectedLog.size()), line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: P + P + F { std::string testLog = LOG_PART + "123\n" + LOG_PART + "456\n" + LOG_FULL + "789"; std::string expectedLog = LOG_PART + "123\n" + LOG_PART + "456\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL("789", line.data.to_string()); APSARA_TEST_EQUAL(int(expectedLog.size()), line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: P + P + F + '\n' { std::string testLog = LOG_PART + "123\n" + LOG_PART + "456\n" + LOG_FULL + "789\n"; std::string expectedLog = LOG_PART + "123\n" + LOG_PART + "456\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL("789", line.data.to_string()); APSARA_TEST_EQUAL(int(expectedLog.size()), line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: P + P + error { std::string testLog = LOG_PART + "123\n" + LOG_PART + "456\n" + LOG_ERROR + "789"; std::string expectedLog = LOG_PART + "123\n" + LOG_PART + "456\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL(LOG_ERROR + "789", line.data.to_string()); APSARA_TEST_EQUAL(int(expectedLog.size()), line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: P + P + error + '\n' { std::string testLog = LOG_PART + "123\n" + LOG_PART + "456\n" + LOG_ERROR + "789\n"; std::string expectedLog = LOG_PART + "123\n" + LOG_PART + "456\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL(LOG_ERROR + "789", line.data.to_string()); APSARA_TEST_EQUAL(int(expectedLog.size()), line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: P + P { std::string testLog = LOG_PART + "123\n" + LOG_PART + "456"; std::string expectedLog = LOG_PART + "123\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(2, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(false, line.fullLine); } // case: P + P + '\n' { std::string testLog = LOG_PART + "123\n" + LOG_PART + "456\n"; std::string expectedLog = LOG_PART + "123\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs, true); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(2, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(false, line.fullLine); } } } void LastMatchedContainerdTextLineUnittest::TestLastContainerdTextLineMerge() { { MultilineOptions multilineOpts; LogFileReader logFileReader(logPathDir, utf8File, DevInode(), std::make_pair(&readerOpts, &ctx), std::make_pair(&multilineOpts, &ctx), std::make_pair(&tagOpts, &ctx)); BaseLineParse* baseLineParsePtr = nullptr; baseLineParsePtr = logFileReader.GetParser<ContainerdTextParser>(LogFileReader::BUFFER_SIZE); logFileReader.mLineParsers.emplace_back(baseLineParsePtr); { { std::string testLog = "\n2024-01-05T23:28:06.818486411+08:00 stdout P 123123\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(0, line.lineEnd); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } { std::string testLog = "\n2024-01-05T23:28:06.818486411+08:00 stdout F 123123\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("123123", line.data.to_string()); APSARA_TEST_EQUAL(1, line.lineBegin); APSARA_TEST_EQUAL(endPs, line.lineEnd); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } } // 异常情况+有回车 { // case: PartLogFlag存在,第三个空格存在但空格后无内容 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout P \n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(false, line.fullLine); } // case: PartLogFlag存在,第三个空格不存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout P\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(false, line.fullLine); } // case: PartLogFlag不存在,第二个空格存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout \n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: 第二个空格不存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(testLog.substr(0, size - 1), line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: 第一个空格不存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00stdout\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(testLog.substr(0, size - 1), line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } } // 异常情况+无回车 { // case: PartLogFlag存在,第三个空格存在但空格后无内容 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout P "; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(false, line.fullLine); } // case: PartLogFlag存在,第三个空格不存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout P"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(false, line.fullLine); } // case: PartLogFlag不存在,第二个空格存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout "; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: 第二个空格不存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00 stdout"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(testLog, line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: 第一个空格不存在 { std::string testLog = "2024-01-05T23:28:06.818486411+08:00stdout"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(testLog, line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } } // case: F + P + P { std::string testLog = LOG_FULL + "789\n" + LOG_PART + "123\n" + LOG_PART + "456"; std::string expectedLog = LOG_FULL + "789\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("789", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(2, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: F + P + P + '\n' { std::string testLog = LOG_FULL + "789\n" + LOG_PART + "123\n" + LOG_PART + "456\n"; std::string expectedLog = LOG_FULL + "789\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("789", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(2, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: F + P + P + F { std::string testLog = LOG_FULL + "789\n" + LOG_PART + "123\n" + LOG_PART + "456\n" + LOG_FULL + "789"; std::string expectedLog = LOG_FULL + "789\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("123456789", line.data.to_string()); APSARA_TEST_EQUAL(int(expectedLog.size()), line.lineBegin); APSARA_TEST_EQUAL(3, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: F + P + P + F + '\n' { std::string testLog = LOG_FULL + "789\n" + LOG_PART + "123\n" + LOG_PART + "456\n" + LOG_FULL + "789\n"; std::string expectedLog = LOG_FULL + "789\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("123456789", line.data.to_string()); APSARA_TEST_EQUAL(int(expectedLog.size()), line.lineBegin); APSARA_TEST_EQUAL(3, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // F + errorLog { std::string testLog = LOG_FULL + "456\n" + LOG_ERROR + "789"; std::string expectedLog = LOG_FULL + "456\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(LOG_ERROR + "789", line.data.to_string()); APSARA_TEST_EQUAL(int(expectedLog.size()), line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // F + errorLog + '\n' { std::string testLog = LOG_FULL + "456\n" + LOG_ERROR + "789\n"; std::string expectedLog = LOG_FULL + "456\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(LOG_ERROR + "789", line.data.to_string()); APSARA_TEST_EQUAL(int(expectedLog.size()), line.lineBegin); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: P + P + F { std::string testLog = LOG_PART + "123\n" + LOG_PART + "456\n" + LOG_FULL + "789"; std::string expectedLog = LOG_PART + "123\n" + LOG_PART + "456\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("123456789", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(3, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: P + P + F + '\n' { std::string testLog = LOG_PART + "123\n" + LOG_PART + "456\n" + LOG_FULL + "789\n"; std::string expectedLog = LOG_PART + "123\n" + LOG_PART + "456\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("123456789", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(3, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: P + P + error { std::string testLog = LOG_PART + "123\n" + LOG_PART + "456\n" + LOG_ERROR + "789"; std::string expectedLog = LOG_PART + "123\n" + LOG_PART + "456\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("123456" + LOG_ERROR + "789", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(3, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: P + P + error + '\n' { std::string testLog = LOG_PART + "123\n" + LOG_PART + "456\n" + LOG_ERROR + "789\n"; std::string expectedLog = LOG_PART + "123\n" + LOG_PART + "456\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("123456" + LOG_ERROR + "789", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(3, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(true, line.fullLine); } // case: P + P { std::string testLog = LOG_PART + "123\n" + LOG_PART + "456"; std::string expectedLog = LOG_PART + "123\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(2, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(false, line.fullLine); } // case: P + P + '\n' { std::string testLog = LOG_PART + "123\n" + LOG_PART + "456\n"; std::string expectedLog = LOG_PART + "123\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(2, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(false, line.fullLine); } } } class LastMatchedDockerJsonFileUnittest : public ::testing::Test { public: static void SetUpTestCase() { logPathDir = GetProcessExecutionDir(); if (PATH_SEPARATOR[0] == logPathDir.back()) { logPathDir.resize(logPathDir.size() - 1); } logPathDir += PATH_SEPARATOR + "testDataSet" + PATH_SEPARATOR + "LogFileReaderUnittest"; gbkFile = "gbk.txt"; utf8File = "utf8.txt"; // content of utf8.txt is equivalent to gbk.txt } static void TearDownTestCase() { remove(gbkFile.c_str()); remove(utf8File.c_str()); } void SetUp() override { std::string filepath = logPathDir + PATH_SEPARATOR + utf8File; std::unique_ptr<FILE, decltype(&std::fclose)> fp(std::fopen(filepath.c_str(), "r"), &std::fclose); if (!fp.get()) { return; } std::fseek(fp.get(), 0, SEEK_END); long filesize = std::ftell(fp.get()); std::fseek(fp.get(), 0, SEEK_SET); expectedContent.reset(new char[filesize + 1]); fread(expectedContent.get(), filesize, 1, fp.get()); expectedContent[filesize] = '\0'; for (long i = filesize - 1; i >= 0; --i) { if (expectedContent[i] == '\n') { expectedContent[i] = 0; break; }; } } void TestLastDockerJsonFile(); std::unique_ptr<char[]> expectedContent; FileReaderOptions readerOpts; FileTagOptions tagOpts; CollectionPipelineContext ctx; static std::string logPathDir; static std::string gbkFile; static std::string utf8File; }; UNIT_TEST_CASE(LastMatchedDockerJsonFileUnittest, TestLastDockerJsonFile); std::string LastMatchedDockerJsonFileUnittest::logPathDir; std::string LastMatchedDockerJsonFileUnittest::gbkFile; std::string LastMatchedDockerJsonFileUnittest::utf8File; void LastMatchedDockerJsonFileUnittest::TestLastDockerJsonFile() { { MultilineOptions multilineOpts; LogFileReader logFileReader(logPathDir, utf8File, DevInode(), std::make_pair(&readerOpts, &ctx), std::make_pair(&multilineOpts, &ctx), std::make_pair(&tagOpts, &ctx)); BaseLineParse* baseLineParsePtr = nullptr; baseLineParsePtr = logFileReader.GetParser<DockerJsonFileParser>(0); logFileReader.mLineParsers.emplace_back(baseLineParsePtr); // 不带回车 // 不带回车 { // 合法 { std::string testLog = R"({"log":"Exception in thread \"main\" java.lang.NullPoinntterException\n","stream":"stdout","time":"2024-02-19T03:49:37.793533014Z"})"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(R"(Exception in thread "main" java.lang.NullPoinntterException)", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(true, line.fullLine); } // log非法 { std::string testLog = R"({"log1":"Exception in thread \"main\" java.lang.NullPoinntterException\n","stream":"stdout","time":"2024-02-19T03:49:37.793533014Z"})"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(false, line.fullLine); } // stream非法 { std::string testLog = R"({"log":"Exception in thread \"main\" java.lang.NullPoinntterException\n","stream1":"stdout","time":"2024-02-19T03:49:37.793533014Z"})"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(false, line.fullLine); } // time非法 { std::string testLog = R"({"log":"Exception in thread \"main\" java.lang.NullPoinntterException\n","stream":"stdout","time1":"2024-02-19T03:49:37.793533014Z"})"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(false, line.fullLine); } // 非法json { std::string testLog = R"(log":"Exception in thread \"main\" java.lang.NullPoinntterException\n","stream":"stdout","time":"2024-02-19T03:49:37.793533014Z"})"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(false, line.fullLine); } } // 带回车 { // 合法 { std::string testLog = R"({"log":"Exception in thread \"main\" java.lang.NullPoinntterException\n","stream":"stdout","time":"2024-02-19T03:49:37.793533014Z"})"; testLog += "\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(1, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(R"(Exception in thread "main" java.lang.NullPoinntterException)", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(true, line.fullLine); } // log非法 { std::string testLog = R"({"log1":"Exception in thread \"main\" java.lang.NullPoinntterException\n","stream":"stdout","time":"2024-02-19T03:49:37.793533014Z"})"; testLog += "\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(false, line.fullLine); } // stream非法 { std::string testLog = R"({"log":"Exception in thread \"main\" java.lang.NullPoinntterException\n","stream1":"stdout","time":"2024-02-19T03:49:37.793533014Z"})"; testLog += "\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(false, line.fullLine); } // time非法 { std::string testLog = R"({"log":"Exception in thread \"main\" java.lang.NullPoinntterException\n","stream":"stdout","time1":"2024-02-19T03:49:37.793533014Z"})"; testLog += "\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(false, line.fullLine); } // 非法json { std::string testLog = R"(log":"Exception in thread \"main\" java.lang.NullPoinntterException\n","stream":"stdout","time":"2024-02-19T03:49:37.793533014Z"})"; testLog += "\n"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(0, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL("", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(false, line.fullLine); } } } } class LastMatchedContainerdTextWithDockerJsonUnittest : public ::testing::Test { public: static void SetUpTestCase() { logPathDir = GetProcessExecutionDir(); if (PATH_SEPARATOR[0] == logPathDir.back()) { logPathDir.resize(logPathDir.size() - 1); } logPathDir += PATH_SEPARATOR + "testDataSet" + PATH_SEPARATOR + "LogFileReaderUnittest"; gbkFile = "gbk.txt"; utf8File = "utf8.txt"; // content of utf8.txt is equivalent to gbk.txt } static void TearDownTestCase() { remove(gbkFile.c_str()); remove(utf8File.c_str()); } void SetUp() override { std::string filepath = logPathDir + PATH_SEPARATOR + utf8File; std::unique_ptr<FILE, decltype(&std::fclose)> fp(std::fopen(filepath.c_str(), "r"), &std::fclose); if (!fp.get()) { return; } std::fseek(fp.get(), 0, SEEK_END); long filesize = std::ftell(fp.get()); std::fseek(fp.get(), 0, SEEK_SET); expectedContent.reset(new char[filesize + 1]); fread(expectedContent.get(), filesize, 1, fp.get()); expectedContent[filesize] = '\0'; for (long i = filesize - 1; i >= 0; --i) { if (expectedContent[i] == '\n') { expectedContent[i] = 0; break; }; } } void TestContainerdTextWithDockerJson(); void TestDockerJsonWithContainerdText(); std::unique_ptr<char[]> expectedContent; FileReaderOptions readerOpts; FileTagOptions tagOpts; CollectionPipelineContext ctx; static std::string logPathDir; static std::string gbkFile; static std::string utf8File; }; UNIT_TEST_CASE(LastMatchedContainerdTextWithDockerJsonUnittest, TestContainerdTextWithDockerJson); UNIT_TEST_CASE(LastMatchedContainerdTextWithDockerJsonUnittest, TestDockerJsonWithContainerdText); std::string LastMatchedContainerdTextWithDockerJsonUnittest::logPathDir; std::string LastMatchedContainerdTextWithDockerJsonUnittest::gbkFile; std::string LastMatchedContainerdTextWithDockerJsonUnittest::utf8File; void LastMatchedContainerdTextWithDockerJsonUnittest::TestContainerdTextWithDockerJson() { MultilineOptions multilineOpts; LogFileReader logFileReader(logPathDir, utf8File, DevInode(), std::make_pair(&readerOpts, &ctx), std::make_pair(&multilineOpts, &ctx), std::make_pair(&tagOpts, &ctx)); BaseLineParse* baseLineParsePtr = nullptr; baseLineParsePtr = logFileReader.GetParser<DockerJsonFileParser>(0); logFileReader.mLineParsers.emplace_back(baseLineParsePtr); baseLineParsePtr = logFileReader.GetParser<ContainerdTextParser>(LogFileReader::BUFFER_SIZE); logFileReader.mLineParsers.emplace_back(baseLineParsePtr); { std::string testLog = R"({"log":"2021-07-13T16:32:21.212861448Z stdout P Exception in thread \"main\" java\n","stream":"stdout","time":"2024-02-19T03:49:37.793533014Z"})"; testLog += "\n"; testLog += R"({"log":"2021-07-13T16:32:21.212861448Z stdout F .lang.NullPoinntterException\n","stream":"stdout","time":"2024-02-19T03:49:37.793533014Z"})"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(2, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(R"(Exception in thread "main" java.lang.NullPoinntterException)", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(true, line.fullLine); } { std::string testLog = R"({"log":"2021-07-13T16:32:21.212861448Z stdout P Exception in thread \"main\" java\n","stream":"stdout","time":"2024-02-19T03:49:37.793533014Z"})"; testLog += "\n"; testLog += R"({"log":"2021-07-13T16:32:21.212861448Z stdout F .lang.NullPoinntterException\n","stream":"stdout","time":"2024-02-19T03:49:37.793533014Z"})"; testLog += "\n"; testLog += R"({"log":"2021-07-13T16:32:21.212861448Z stdout P 哈哈哈哈\n","stream":"stdout","time":"2024-02-19T03:49:37.79353)"; testLog += "\n"; testLog += R"({"log":"2021-07-13T16:32:21.212861448Z stdout F 啦啦啦啦\n","stream":"stdout","time":"2024-02-19T03:49:37.79353)"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(2, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(0, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(R"(Exception in thread "main" java.lang.NullPoinntterException)", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(true, line.fullLine); } } void LastMatchedContainerdTextWithDockerJsonUnittest::TestDockerJsonWithContainerdText() { MultilineOptions multilineOpts; LogFileReader logFileReader(logPathDir, utf8File, DevInode(), std::make_pair(&readerOpts, &ctx), std::make_pair(&multilineOpts, &ctx), std::make_pair(&tagOpts, &ctx)); BaseLineParse* baseLineParsePtr = nullptr; baseLineParsePtr = logFileReader.GetParser<ContainerdTextParser>(LogFileReader::BUFFER_SIZE); logFileReader.mLineParsers.emplace_back(baseLineParsePtr); baseLineParsePtr = logFileReader.GetParser<DockerJsonFileParser>(0); logFileReader.mLineParsers.emplace_back(baseLineParsePtr); { std::string testLog = R"(2021-07-13T16:32:21.212861448Z stdout P {"log":"Exception in thread \"main\" java.lang.NullPoinntterException\n","stream":"stdout","t)"; testLog += "\n"; testLog += R"(2021-07-13T16:32:21.212861448Z stdout F ime":"2024-02-19T03:49:37.793533014Z"})"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(2, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(R"(Exception in thread "main" java.lang.NullPoinntterException)", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(true, line.fullLine); } { std::string testLog = R"(2021-07-13T16:32:21.212861448Z stdout P {"log":"Exception in thread \"main\" java.lang.NullPoinntterEx)"; testLog += "\n"; testLog += R"(2021-07-13T16:32:21.212861448Z stdout F ception\n","stream":"stdout","time":"2024-02-19T03:49:37.793533014Z"})"; testLog += "\n"; testLog += R"(2021-07-13T16:32:21.212861448Z stdo)"; int32_t size = testLog.size(); int32_t endPs; // the position of \n or \0 if (testLog[size - 1] == '\n') { endPs = size - 1; } else { endPs = size; } LineInfo line = logFileReader.GetLastLine(testLog, endPs); APSARA_TEST_EQUAL(2, line.rollbackLineFeedCount); APSARA_TEST_EQUAL(1, line.forceRollbackLineFeedCount); APSARA_TEST_EQUAL(R"(Exception in thread "main" java.lang.NullPoinntterException)", line.data.to_string()); APSARA_TEST_EQUAL(0, line.lineBegin); APSARA_TEST_EQUAL(true, line.fullLine); } } } // namespace logtail UNIT_TEST_MAIN