core/unittest/reader/RemoveLastIncompleteLogUnittest.cpp (1,178 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 "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
#include "FileTagOptions.h"
#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_BEGIN_STRING = "Exception in thread \"main\" java.lang.NullPointerException";
const std::string LOG_BEGIN_REGEX = R"(Exception.*)";
const std::string LOG_CONTINUE_STRING = " at com.example.myproject.Book.getTitle(Book.java:16)";
const std::string LOG_CONTINUE_REGEX = R"(\s+at\s.*)";
const std::string LOG_END_STRING = " ...23 more";
const std::string LOG_END_REGEX = R"(\s*\.\.\.\d+ more)";
const std::string LOG_UNMATCH = "unmatch log";
class RemoveLastIncompleteLogUnittest : 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 {
readerOpts.mInputType = FileReaderOptions::InputType::InputFile;
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 TestSingleline();
void TestMultiline();
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(RemoveLastIncompleteLogUnittest, TestSingleline);
UNIT_TEST_CASE(RemoveLastIncompleteLogUnittest, TestMultiline);
std::string RemoveLastIncompleteLogUnittest::logPathDir;
std::string RemoveLastIncompleteLogUnittest::gbkFile;
std::string RemoveLastIncompleteLogUnittest::utf8File;
void RemoveLastIncompleteLogUnittest::TestSingleline() {
MultilineOptions multilineOpts;
LogFileReader logFileReader(logPathDir,
utf8File,
DevInode(),
std::make_pair(&readerOpts, &ctx),
std::make_pair(&multilineOpts, &ctx),
std::make_pair(&tagOpts, &ctx));
{ // case single line
std::string line1 = "first.";
std::string line2 = "second.";
std::string line3 = "third.";
std::string expectMatch = line1 + '\n' + line2 + '\n' + line3 + '\n';
std::string testLog = expectMatch;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(0, rollbackLineFeedCount);
}
{ // case single line, buffer size not big enough (no new line at the end of line)
std::string line1 = "first.";
std::string line2 = "second.";
std::string line3 = "third_part.";
std::string expectMatch = line1 + '\n' + line2 + '\n';
std::string testLog = expectMatch + line3;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
{ // case single line, cannot be split, buffer size not big enough (no new line at the end of line)
// it will be force read in ReadUTF8/ReadGBK
std::string testLog = "first.";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(0, matchSize);
// return the whole buffer, so no rollback
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
{ // case empty string
std::string expectMatch = "";
int32_t rollbackLineFeedCount = 0;
std::string testLog2 = expectMatch + "";
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog2.data()), testLog2.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(0, rollbackLineFeedCount);
}
}
void RemoveLastIncompleteLogUnittest::TestMultiline() {
Json::Value config;
config["StartPattern"] = LOG_BEGIN_REGEX;
MultilineOptions multilineOpts;
multilineOpts.Init(config, ctx, "");
LogFileReader logFileReader(logPathDir,
utf8File,
DevInode(),
std::make_pair(&readerOpts, &ctx),
std::make_pair(&multilineOpts, &ctx),
std::make_pair(&tagOpts, &ctx));
{ // case multi line
std::vector<int32_t> index;
std::string firstLog = LOG_BEGIN_STRING + "first.\nmultiline1\nmultiline2";
std::string secondLog = LOG_BEGIN_STRING + "second.\nmultiline1\nmultiline2";
std::string expectMatch = firstLog + '\n';
std::string testLog = expectMatch + secondLog + '\n';
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(3, rollbackLineFeedCount);
}
{ // case multi line, buffer size not big enough (no new line at the end of line)
std::vector<int32_t> index;
std::string firstLog = LOG_BEGIN_STRING + "first.\nmultiline1\nmultiline2";
std::string secondLog = LOG_BEGIN_STRING + "second.\nmultiline1\nmultiline2";
std::string expectMatch = firstLog + '\n';
std::string testLog = expectMatch + secondLog;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(3, rollbackLineFeedCount);
}
{ // case multi line not match
std::string testLog2 = "log begin does not match.\nlog begin does not match.\nlog begin does not match.\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog2.data()), testLog2.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(int32_t(testLog2.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(0, rollbackLineFeedCount);
}
{ // case multi line not match, buffer size not big enough (no new line at the end of line)
std::string expectMatch = "log begin does not match.\nlog begin does not match.\n";
std::string testLog2 = expectMatch + "log begin does not";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog2.data()), testLog2.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
{ // case empty string
std::string expectMatch = "";
int32_t rollbackLineFeedCount = 0;
std::string testLog2 = expectMatch + "";
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog2.data()), testLog2.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(0, rollbackLineFeedCount);
}
}
class RemoveLastIncompleteLogMultilineUnittest : public ::testing::Test {
public:
void TestRemoveLastIncompleteLogWithBeginContinue();
void TestRemoveLastIncompleteLogWithBeginEnd();
void TestRemoveLastIncompleteLogWithBegin();
void TestRemoveLastIncompleteLogWithContinueEnd();
void TestRemoveLastIncompleteLogWithEnd();
void SetUp() override { readerOpts.mInputType = FileReaderOptions::InputType::InputFile; }
private:
FileReaderOptions readerOpts;
FileTagOptions tagOpts;
CollectionPipelineContext ctx;
};
UNIT_TEST_CASE(RemoveLastIncompleteLogMultilineUnittest, TestRemoveLastIncompleteLogWithBeginContinue);
UNIT_TEST_CASE(RemoveLastIncompleteLogMultilineUnittest, TestRemoveLastIncompleteLogWithBeginEnd);
UNIT_TEST_CASE(RemoveLastIncompleteLogMultilineUnittest, TestRemoveLastIncompleteLogWithBegin);
UNIT_TEST_CASE(RemoveLastIncompleteLogMultilineUnittest, TestRemoveLastIncompleteLogWithContinueEnd);
UNIT_TEST_CASE(RemoveLastIncompleteLogMultilineUnittest, TestRemoveLastIncompleteLogWithEnd);
void RemoveLastIncompleteLogMultilineUnittest::TestRemoveLastIncompleteLogWithBeginContinue() {
Json::Value config;
config["StartPattern"] = LOG_BEGIN_REGEX;
config["ContinuePattern"] = LOG_CONTINUE_REGEX;
MultilineOptions multilineOpts;
multilineOpts.Init(config, ctx, "");
LogFileReader logFileReader("dir",
"file",
DevInode(),
std::make_pair(&readerOpts, &ctx),
std::make_pair(&multilineOpts, &ctx),
std::make_pair(&tagOpts, &ctx));
// logFileReader.mDiscardUnmatch = true;
{ // case: end with begin continue
std::string expectMatch = LOG_BEGIN_STRING + "\n" + LOG_CONTINUE_STRING + "\n" + LOG_CONTINUE_STRING + '\n';
std::string testLog = expectMatch + LOG_BEGIN_STRING + "\n" + LOG_CONTINUE_STRING + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(2, rollbackLineFeedCount);
}
{ // case: end with begin
std::string expectMatch = LOG_BEGIN_STRING + "\n" + LOG_CONTINUE_STRING + "\n" + LOG_CONTINUE_STRING + '\n';
std::string testLog = expectMatch + LOG_BEGIN_STRING + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
{ // case: end with unmatch
std::string expectMatch = LOG_BEGIN_STRING + "\n" + LOG_CONTINUE_STRING + "\n" + LOG_CONTINUE_STRING + "\n";
std::string testLog = expectMatch + LOG_BEGIN_STRING + "\n" + LOG_UNMATCH + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(2, rollbackLineFeedCount);
}
{ // case: all unmatch
std::string expectMatch = "\n\n";
std::string testLog = expectMatch + LOG_UNMATCH;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
}
void RemoveLastIncompleteLogMultilineUnittest::TestRemoveLastIncompleteLogWithBeginEnd() {
Json::Value config;
config["StartPattern"] = LOG_BEGIN_REGEX;
config["EndPattern"] = LOG_END_REGEX;
MultilineOptions multilineOpts;
multilineOpts.Init(config, ctx, "");
LogFileReader logFileReader("dir",
"file",
DevInode(),
std::make_pair(&readerOpts, &ctx),
std::make_pair(&multilineOpts, &ctx),
std::make_pair(&tagOpts, &ctx));
// logFileReader.mDiscardUnmatch = true;
{ // case: end with begin end
std::string expectMatch = LOG_BEGIN_STRING + "\n" + LOG_UNMATCH + "\n" + LOG_END_STRING + '\n';
std::string testLog = std::string(expectMatch.data());
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(0, rollbackLineFeedCount);
}
{ // case: end with begin
std::string expectMatch = LOG_BEGIN_STRING + "\n" + LOG_UNMATCH + "\n" + LOG_END_STRING + '\n';
std::string testLog = expectMatch + LOG_BEGIN_STRING + LOG_BEGIN_STRING + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
{ // case: end with unmatch
std::string expectMatch = LOG_BEGIN_STRING + "\n" + LOG_UNMATCH + "\n" + LOG_END_STRING + "\n";
std::string testLog = expectMatch + LOG_UNMATCH + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
{ // case: all unmatch
std::string expectMatch = "\n\n";
std::string testLog = expectMatch + LOG_UNMATCH;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
}
void RemoveLastIncompleteLogMultilineUnittest::TestRemoveLastIncompleteLogWithBegin() {
Json::Value config;
config["StartPattern"] = LOG_BEGIN_REGEX;
MultilineOptions multilineOpts;
multilineOpts.Init(config, ctx, "");
LogFileReader logFileReader("dir",
"file",
DevInode(),
std::make_pair(&readerOpts, &ctx),
std::make_pair(&multilineOpts, &ctx),
std::make_pair(&tagOpts, &ctx));
// logFileReader.mDiscardUnmatch = true;
{ // case: end with begin
std::string expectMatch = LOG_BEGIN_STRING + "\n" + LOG_UNMATCH + "\n" + LOG_UNMATCH + '\n';
std::string testLog = expectMatch + LOG_BEGIN_STRING;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
{ // case: end with unmatch
std::string expectMatch = LOG_BEGIN_STRING + "\n" + LOG_UNMATCH + "\n" + LOG_UNMATCH + "\n";
std::string testLog = expectMatch + LOG_BEGIN_STRING + "\n" + LOG_UNMATCH + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(2, rollbackLineFeedCount);
}
{ // case: all unmatch
std::string expectMatch = "\n\n";
std::string testLog = expectMatch + LOG_UNMATCH;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
}
void RemoveLastIncompleteLogMultilineUnittest::TestRemoveLastIncompleteLogWithContinueEnd() {
Json::Value config;
config["ContinuePattern"] = LOG_CONTINUE_REGEX;
config["EndPattern"] = LOG_END_REGEX;
MultilineOptions multilineOpts;
multilineOpts.Init(config, ctx, "");
LogFileReader logFileReader("dir",
"file",
DevInode(),
std::make_pair(&readerOpts, &ctx),
std::make_pair(&multilineOpts, &ctx),
std::make_pair(&tagOpts, &ctx));
// logFileReader.mDiscardUnmatch = true;
{ // case: end with continue end
std::string expectMatch = LOG_CONTINUE_STRING + "\n" + LOG_CONTINUE_STRING + "\n" + LOG_END_STRING + '\n';
std::string testLog = std::string(expectMatch.data());
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(0, rollbackLineFeedCount);
}
{ // case: end with continue
std::string expectMatch = LOG_CONTINUE_STRING + "\n" + LOG_CONTINUE_STRING + "\n" + LOG_END_STRING + '\n';
std::string testLog = expectMatch + LOG_CONTINUE_STRING + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
{ // case: end with unmatch
std::string expectMatch = LOG_CONTINUE_STRING + "\n" + LOG_CONTINUE_STRING + "\n" + LOG_END_STRING + "\n";
std::string testLog = expectMatch + LOG_UNMATCH + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
{ // case: only \n
std::string expectMatch = "\n\n";
std::string testLog = expectMatch + LOG_UNMATCH;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
}
void RemoveLastIncompleteLogMultilineUnittest::TestRemoveLastIncompleteLogWithEnd() {
Json::Value config;
config["EndPattern"] = LOG_END_REGEX;
MultilineOptions multilineOpts;
multilineOpts.Init(config, ctx, "");
LogFileReader logFileReader("dir",
"file",
DevInode(),
std::make_pair(&readerOpts, &ctx),
std::make_pair(&multilineOpts, &ctx),
std::make_pair(&tagOpts, &ctx));
// logFileReader.mDiscardUnmatch = true;
{ // case: end with end
{
std::string expectMatch = LOG_UNMATCH + "\n" + LOG_UNMATCH + "\n" + LOG_END_STRING + '\n';
std::string testLog = std::string(expectMatch.data());
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(0, rollbackLineFeedCount);
}
{
std::string expectMatch = LOG_UNMATCH + "\n" + LOG_UNMATCH + "\n" + LOG_END_STRING;
std::string testLog = std::string(expectMatch.data());
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL(0, matchSize);
APSARA_TEST_EQUAL(std::string(testLog.data(), matchSize), "");
APSARA_TEST_EQUAL(3, rollbackLineFeedCount);
}
} // namespace logtail
{ // case: end with unmatch
std::string expectMatch = LOG_UNMATCH + "\n" + LOG_UNMATCH + "\n" + LOG_END_STRING + '\n';
std::string testLog = expectMatch + LOG_UNMATCH + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
{ // case: all unmatch
{
std::string expectMatch = "\n\n";
std::string testLog = expectMatch + LOG_UNMATCH;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL_FATAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL_FATAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL_FATAL(1, rollbackLineFeedCount);
}
{
std::string expectMatch = "\n\n" + LOG_UNMATCH + "\n";
std::string testLog = expectMatch;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
APSARA_TEST_EQUAL(static_cast<int32_t>(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(std::string(testLog.data(), matchSize), expectMatch);
APSARA_TEST_EQUAL(0, rollbackLineFeedCount);
}
}
}
class GetLastLineUnittest : public ::testing::Test {
public:
void TestGetLastLine();
void TestGetLastLineEmpty();
private:
FileReaderOptions readerOpts;
CollectionPipelineContext ctx;
};
UNIT_TEST_CASE(GetLastLineUnittest, TestGetLastLine);
UNIT_TEST_CASE(GetLastLineUnittest, TestGetLastLineEmpty);
void GetLastLineUnittest::TestGetLastLine() {
std::string testLog = "first line\nsecond line\nthird line";
LogFileReader logFileReader("dir",
"file",
DevInode(),
std::make_pair(&readerOpts, &ctx),
std::make_pair(nullptr, &ctx),
std::make_pair(nullptr, &ctx));
auto lastLine = logFileReader.GetLastLine(const_cast<char*>(testLog.data()), testLog.size());
std::string expectLog = "third line";
APSARA_TEST_EQUAL_FATAL(expectLog, std::string(lastLine.data.data(), lastLine.data.size()));
}
void GetLastLineUnittest::TestGetLastLineEmpty() {
std::string testLog = "";
LogFileReader logFileReader("dir",
"file",
DevInode(),
std::make_pair(&readerOpts, &ctx),
std::make_pair(nullptr, &ctx),
std::make_pair(nullptr, &ctx));
auto lastLine = logFileReader.GetLastLine(const_cast<char*>(testLog.data()), testLog.size());
APSARA_TEST_EQUAL_FATAL(0, int(lastLine.data.size()));
APSARA_TEST_EQUAL_FATAL("", std::string(lastLine.data.data(), lastLine.data.size()));
APSARA_TEST_EQUAL_FATAL(testLog.data(), lastLine.data);
}
class ContainerdTextRemoveLastIncompleteLogMultilineUnittest : public ::testing::Test {
public:
void TestRemoveLastIncompleteLogWithBeginEnd();
void TestRemoveLastIncompleteLogWithBegin();
void TestRemoveLastIncompleteLogWithEnd();
void SetUp() override { readerOpts.mInputType = FileReaderOptions::InputType::InputContainerStdio; }
private:
FileReaderOptions readerOpts;
CollectionPipelineContext ctx;
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";
const std::string LOG_BEGIN_STRING = "Exception in thread \"main\" java.lang.NullPointerException";
const std::string LOG_BEGIN_REGEX = R"(Exception.*)";
const std::string LOG_END_STRING = " ...23 more";
const std::string LOG_END_REGEX = R"(\s*\.\.\.\d+ more.*)";
const std::string LOG_UNMATCH = "unmatch log";
};
UNIT_TEST_CASE(ContainerdTextRemoveLastIncompleteLogMultilineUnittest, TestRemoveLastIncompleteLogWithBeginEnd);
UNIT_TEST_CASE(ContainerdTextRemoveLastIncompleteLogMultilineUnittest, TestRemoveLastIncompleteLogWithBegin);
UNIT_TEST_CASE(ContainerdTextRemoveLastIncompleteLogMultilineUnittest, TestRemoveLastIncompleteLogWithEnd);
void ContainerdTextRemoveLastIncompleteLogMultilineUnittest::TestRemoveLastIncompleteLogWithBeginEnd() {
Json::Value config;
config["StartPattern"] = LOG_BEGIN_REGEX;
config["EndPattern"] = LOG_END_REGEX;
MultilineOptions multilineOpts;
multilineOpts.Init(config, ctx, "");
LogFileReader logFileReader("dir",
"file",
DevInode(),
std::make_pair(&readerOpts, &ctx),
std::make_pair(&multilineOpts, &ctx),
std::make_pair(nullptr, &ctx));
BaseLineParse* baseLineParsePtr = nullptr;
baseLineParsePtr = logFileReader.GetParser<ContainerdTextParser>(LogFileReader::BUFFER_SIZE);
logFileReader.mLineParsers.emplace_back(baseLineParsePtr);
{ // case: end with begin end
std::string expectMatch
= LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_END_STRING + '\n';
std::string testLog = std::string(expectMatch.data());
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(0, rollbackLineFeedCount);
}
{ // case: end with begin
std::string expectMatch
= LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_END_STRING + '\n';
std::string testLog = expectMatch + LOG_FULL + LOG_BEGIN_STRING + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(1, rollbackLineFeedCount);
}
{ // case: end with unmatch
std::string expectMatch
= LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_END_STRING + "\n";
std::string testLog = expectMatch + LOG_FULL + LOG_UNMATCH + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(1, rollbackLineFeedCount);
}
{ // case: all unmatch
std::string expectMatch = "\n\n";
std::string testLog = expectMatch + LOG_FULL + LOG_UNMATCH;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(1, rollbackLineFeedCount);
}
}
void ContainerdTextRemoveLastIncompleteLogMultilineUnittest::TestRemoveLastIncompleteLogWithBegin() {
Json::Value config;
config["StartPattern"] = LOG_BEGIN_REGEX;
MultilineOptions multilineOpts;
multilineOpts.Init(config, ctx, "");
LogFileReader logFileReader("dir",
"file",
DevInode(),
std::make_pair(&readerOpts, &ctx),
std::make_pair(&multilineOpts, &ctx),
std::make_pair(nullptr, &ctx));
BaseLineParse* baseLineParsePtr = nullptr;
baseLineParsePtr = logFileReader.GetParser<ContainerdTextParser>(LogFileReader::BUFFER_SIZE);
logFileReader.mLineParsers.emplace_back(baseLineParsePtr);
{ // case: end with begin
{
std::string expectMatch
= LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + '\n';
std::string testLog = expectMatch + LOG_PART + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(2, rollbackLineFeedCount);
}
{
std::string expectMatch
= LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + '\n';
std::string testLog = expectMatch + LOG_PART + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(2, rollbackLineFeedCount);
}
{
std::string expectMatch
= LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + '\n';
std::string testLog = expectMatch + LOG_FULL + LOG_BEGIN_STRING + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(1, rollbackLineFeedCount);
}
{
std::string expectMatch
= LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + '\n';
std::string testLog = expectMatch + LOG_FULL + LOG_BEGIN_STRING;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(1, rollbackLineFeedCount);
}
}
{ // case: end with unmatch
{
std::string expectMatch
= LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + "\n";
std::string testLog = expectMatch + LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(2, rollbackLineFeedCount);
}
{
std::string expectMatch
= LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + "\n";
std::string testLog = expectMatch + LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(2, rollbackLineFeedCount);
}
}
{ // case: all unmatch
{
std::string expectMatch = "\n\n" + LOG_FULL + LOG_UNMATCH + "\n";
std::string testLog = expectMatch;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(0, rollbackLineFeedCount);
}
{
std::string expectMatch = "\n\n";
std::string testLog = expectMatch + LOG_FULL + LOG_UNMATCH;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(1, rollbackLineFeedCount);
}
{
std::string expectMatch = "\n\n" + LOG_FULL + LOG_UNMATCH + "\n";
std::string testLog = expectMatch + LOG_PART + LOG_BEGIN_STRING + "\n" + LOG_PART + LOG_BEGIN_STRING + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(2, rollbackLineFeedCount);
}
{
std::string expectMatch = "\n\n" + LOG_FULL + LOG_UNMATCH + "\n";
std::string testLog = expectMatch + LOG_PART + LOG_BEGIN_STRING + "\n" + LOG_PART + LOG_BEGIN_STRING;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(2, rollbackLineFeedCount);
}
}
{ // case: end with part log
{
std::string expectMatch
= LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + '\n';
std::string testLog = expectMatch + LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_PART + LOG_BEGIN_STRING + "\n"
+ LOG_PART + LOG_BEGIN_STRING + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(3, rollbackLineFeedCount);
}
{
std::string expectMatch
= LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + '\n';
std::string testLog = expectMatch + LOG_FULL + LOG_BEGIN_STRING + "\n" + LOG_PART + LOG_BEGIN_STRING + "\n"
+ LOG_PART + LOG_BEGIN_STRING;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(3, rollbackLineFeedCount);
}
}
}
void ContainerdTextRemoveLastIncompleteLogMultilineUnittest::TestRemoveLastIncompleteLogWithEnd() {
Json::Value config;
config["EndPattern"] = LOG_END_REGEX;
MultilineOptions multilineOpts;
multilineOpts.Init(config, ctx, "");
LogFileReader logFileReader("dir",
"file",
DevInode(),
std::make_pair(&readerOpts, &ctx),
std::make_pair(&multilineOpts, &ctx),
std::make_pair(nullptr, &ctx));
BaseLineParse* baseLineParsePtr = nullptr;
baseLineParsePtr = logFileReader.GetParser<ContainerdTextParser>(LogFileReader::BUFFER_SIZE);
logFileReader.mLineParsers.emplace_back(baseLineParsePtr);
{ // case: end with end
{
std::string expectMatch = LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_PART
+ LOG_END_STRING + '\n' + LOG_FULL + LOG_UNMATCH;
std::string testLog = expectMatch;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(0, matchSize);
APSARA_TEST_EQUAL("", matchLog);
APSARA_TEST_EQUAL(4, rollbackLineFeedCount);
}
{
std::string expectMatch = LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_PART
+ LOG_END_STRING + '\n' + LOG_FULL + LOG_UNMATCH + '\n';
std::string testLog = expectMatch;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(0, rollbackLineFeedCount);
}
{
std::string expectMatch
= LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_END_STRING + '\n';
std::string testLog = expectMatch;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(0, rollbackLineFeedCount);
}
{
std::string expectMatch
= LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_END_STRING;
std::string testLog = expectMatch;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(0, matchSize);
APSARA_TEST_EQUAL("", matchLog);
APSARA_TEST_EQUAL(3, rollbackLineFeedCount);
}
}
{ // case: end with unmatch
std::string expectMatch
= LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_END_STRING + '\n';
std::string testLog = expectMatch + LOG_FULL + LOG_UNMATCH + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(1, rollbackLineFeedCount);
}
{ // case: all unmatch
{
std::string expectMatch = "\n\n";
std::string testLog = expectMatch + LOG_FULL + LOG_UNMATCH;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(1, rollbackLineFeedCount);
}
{
std::string expectMatch = "\n\n" + LOG_FULL + LOG_UNMATCH + "\n";
std::string testLog = expectMatch;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(0, rollbackLineFeedCount);
}
}
{ // case: end with part log
{
std::string expectMatch
= LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_END_STRING + '\n';
std::string testLog
= expectMatch + LOG_PART + LOG_UNMATCH + "\n" + LOG_PART + LOG_UNMATCH + "\n" + LOG_PART + LOG_UNMATCH;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(3, rollbackLineFeedCount);
}
{
std::string expectMatch
= LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_END_STRING + '\n';
std::string testLog = expectMatch + LOG_PART + LOG_UNMATCH + "\n" + LOG_PART + LOG_UNMATCH + "\n" + LOG_PART
+ LOG_UNMATCH + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(3, rollbackLineFeedCount);
}
{
std::string expectMatch
= LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_UNMATCH + "\n" + LOG_FULL + LOG_END_STRING + '\n';
std::string testLog = expectMatch + LOG_PART + LOG_UNMATCH + "\n" + LOG_PART + LOG_UNMATCH + "\n"
+ "2021-08-25T07:00:00.000000000Z";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(3, rollbackLineFeedCount);
}
}
}
class DockerJsonRemoveLastIncompleteLogMultilineUnittest : public ::testing::Test {
public:
void TestRemoveLastIncompleteLogWithBeginEnd();
void TestRemoveLastIncompleteLogWithBegin();
void TestRemoveLastIncompleteLogWithEnd();
void SetUp() override { readerOpts.mInputType = FileReaderOptions::InputType::InputContainerStdio; }
private:
FileReaderOptions readerOpts;
CollectionPipelineContext ctx;
const std::string LOG_BEGIN_STRING = "Exception in thread \"main\" java.lang.NullPointerException";
const std::string LOG_BEGIN_REGEX = R"(Exception.*)";
const std::string LOG_END_STRING = " ...23 more";
const std::string LOG_END_REGEX = R"(\s*\.\.\.\d+ more.*)";
const std::string LOG_UNMATCH = "unmatch log";
std::string BuildLog(const std::string& log, bool isNormalLog = true) {
if (isNormalLog) {
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
writer.StartObject();
writer.Key("log");
writer.String((log + "\\n").c_str());
writer.Key("stream");
writer.String("stdout");
writer.Key("time");
writer.String("2024-02-19T03:49:37.793533014Z");
writer.EndObject();
return buffer.GetString();
} else {
return R"({"log":")" + log + R"(\n","stream":"stdout","time":"2024-02-19T03:49:37.79)";
}
}
};
UNIT_TEST_CASE(DockerJsonRemoveLastIncompleteLogMultilineUnittest, TestRemoveLastIncompleteLogWithBegin);
UNIT_TEST_CASE(DockerJsonRemoveLastIncompleteLogMultilineUnittest, TestRemoveLastIncompleteLogWithEnd);
void DockerJsonRemoveLastIncompleteLogMultilineUnittest::TestRemoveLastIncompleteLogWithBegin() {
Json::Value config;
config["StartPattern"] = LOG_BEGIN_REGEX;
MultilineOptions multilineOpts;
multilineOpts.Init(config, ctx, "");
LogFileReader logFileReader("dir",
"file",
DevInode(),
std::make_pair(&readerOpts, &ctx),
std::make_pair(&multilineOpts, &ctx),
std::make_pair(nullptr, &ctx));
BaseLineParse* baseLineParsePtr = nullptr;
baseLineParsePtr = logFileReader.GetParser<DockerJsonFileParser>(0);
logFileReader.mLineParsers.emplace_back(baseLineParsePtr);
{ // case: end with begin
{
std::string expectMatch
= BuildLog(LOG_BEGIN_STRING) + "\n" + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH) + '\n';
std::string testLog = expectMatch + BuildLog(LOG_BEGIN_STRING) + "\n" + BuildLog(LOG_UNMATCH);
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(2, rollbackLineFeedCount);
}
{
std::string expectMatch
= BuildLog(LOG_BEGIN_STRING) + "\n" + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH) + '\n';
std::string testLog = expectMatch + BuildLog(LOG_BEGIN_STRING) + "\n" + BuildLog(LOG_UNMATCH) + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(2, rollbackLineFeedCount);
}
{
std::string expectMatch
= BuildLog(LOG_BEGIN_STRING) + "\n" + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH) + '\n';
std::string testLog = expectMatch + BuildLog(LOG_BEGIN_STRING) + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(1, rollbackLineFeedCount);
}
{
std::string expectMatch
= BuildLog(LOG_BEGIN_STRING) + "\n" + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH) + '\n';
std::string testLog = expectMatch + BuildLog(LOG_BEGIN_STRING);
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(1, rollbackLineFeedCount);
}
}
{ // case: end with unmatch
{
std::string expectMatch
= BuildLog(LOG_BEGIN_STRING) + "\n" + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH) + "\n";
std::string testLog = expectMatch + BuildLog(LOG_BEGIN_STRING) + "\n" + BuildLog(LOG_UNMATCH) + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(2, rollbackLineFeedCount);
}
{
std::string expectMatch
= BuildLog(LOG_BEGIN_STRING) + "\n" + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH) + "\n";
std::string testLog = expectMatch + BuildLog(LOG_BEGIN_STRING) + "\n" + BuildLog(LOG_UNMATCH);
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(2, rollbackLineFeedCount);
}
}
{ // case: all unmatch
{
std::string expectMatch = "\n\n" + BuildLog(LOG_UNMATCH) + "\n";
std::string testLog = expectMatch;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(0, rollbackLineFeedCount);
}
{
std::string expectMatch = "\n\n";
std::string testLog = expectMatch + BuildLog(LOG_UNMATCH);
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(1, rollbackLineFeedCount);
}
}
{ // case: end with part log
{
std::string expectMatch
= BuildLog(LOG_BEGIN_STRING) + "\n" + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH) + '\n';
std::string testLog = expectMatch + BuildLog(LOG_BEGIN_STRING) + "\n" + BuildLog(LOG_BEGIN_STRING, false)
+ "\n" + BuildLog(LOG_BEGIN_STRING, false) + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(3, rollbackLineFeedCount);
}
{
std::string expectMatch
= BuildLog(LOG_BEGIN_STRING) + "\n" + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH) + '\n';
std::string testLog = expectMatch + BuildLog(LOG_BEGIN_STRING) + "\n" + BuildLog(LOG_BEGIN_STRING, false)
+ "\n" + BuildLog(LOG_BEGIN_STRING, false);
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(3, rollbackLineFeedCount);
}
}
}
void DockerJsonRemoveLastIncompleteLogMultilineUnittest::TestRemoveLastIncompleteLogWithEnd() {
Json::Value config;
config["EndPattern"] = LOG_END_REGEX;
MultilineOptions multilineOpts;
multilineOpts.Init(config, ctx, "");
LogFileReader logFileReader("dir",
"file",
DevInode(),
std::make_pair(&readerOpts, &ctx),
std::make_pair(&multilineOpts, &ctx),
std::make_pair(nullptr, &ctx));
BaseLineParse* baseLineParsePtr = nullptr;
baseLineParsePtr = logFileReader.GetParser<DockerJsonFileParser>(0);
logFileReader.mLineParsers.emplace_back(baseLineParsePtr);
{ // case: end with end
{
std::string expectMatch
= BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_END_STRING);
std::string testLog = expectMatch;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(0, matchSize);
APSARA_TEST_EQUAL("", matchLog);
APSARA_TEST_EQUAL(3, rollbackLineFeedCount);
}
{
std::string expectMatch
= BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_END_STRING) + '\n';
std::string testLog = expectMatch;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(0, rollbackLineFeedCount);
}
}
{ // case: end with unmatch
std::string expectMatch
= BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_END_STRING) + '\n';
std::string testLog = expectMatch + BuildLog(LOG_UNMATCH) + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(1, rollbackLineFeedCount);
}
{ // case: all unmatch
{
std::string expectMatch = "\n\n";
std::string testLog = expectMatch + BuildLog(LOG_UNMATCH);
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(1, rollbackLineFeedCount);
}
{
std::string expectMatch = "\n\n" + BuildLog(LOG_UNMATCH) + "\n";
std::string testLog = expectMatch;
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(0, rollbackLineFeedCount);
}
}
{ // case: end with part log
{
std::string expectMatch
= BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_END_STRING) + '\n';
std::string testLog = expectMatch + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH, false) + "\n"
+ BuildLog(LOG_UNMATCH, false);
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(3, rollbackLineFeedCount);
}
{
std::string expectMatch
= BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_END_STRING) + '\n';
std::string testLog = expectMatch + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH, false) + "\n"
+ BuildLog(LOG_UNMATCH, false) + "\n";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(3, rollbackLineFeedCount);
}
{
std::string expectMatch
= BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_END_STRING) + '\n';
std::string testLog = expectMatch + BuildLog(LOG_UNMATCH) + "\n" + BuildLog(LOG_UNMATCH, false) + "\n"
+ "2021-08-25T07:00:00.000000000Z";
int32_t rollbackLineFeedCount = 0;
int32_t matchSize = logFileReader.RemoveLastIncompleteLog(
const_cast<char*>(testLog.data()), testLog.size(), rollbackLineFeedCount);
const auto& matchLog = std::string(testLog.data(), matchSize);
APSARA_TEST_EQUAL(int32_t(expectMatch.size()), matchSize);
APSARA_TEST_EQUAL(expectMatch, matchLog);
APSARA_TEST_EQUAL(3, rollbackLineFeedCount);
}
}
}
} // namespace logtail
UNIT_TEST_MAIN