aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoralexvru <alexvru@ydb.tech>2022-11-03 10:35:20 +0300
committeralexvru <alexvru@ydb.tech>2022-11-03 10:35:20 +0300
commit5b229b5f88be3141722b369f4fb13bb933c29a28 (patch)
tree630d94aab932344b0f1fa4b07a289f83d1f82c1f
parent3910880160a4aaae4c26adeea4fe525e91856737 (diff)
downloadydb-5b229b5f88be3141722b369f4fb13bb933c29a28.tar.gz
Make stlog a bit better
-rw-r--r--ydb/core/keyvalue/keyvalue_storage_read_request.cpp14
-rw-r--r--ydb/core/util/CMakeLists.txt2
-rw-r--r--ydb/core/util/stlog.cpp17
-rw-r--r--ydb/core/util/stlog.h244
-rw-r--r--ydb/core/util/stlog_ut.cpp41
-rw-r--r--ydb/core/util/ut/CMakeLists.darwin.txt1
-rw-r--r--ydb/core/util/ut/CMakeLists.linux-aarch64.txt1
-rw-r--r--ydb/core/util/ut/CMakeLists.linux.txt1
8 files changed, 243 insertions, 78 deletions
diff --git a/ydb/core/keyvalue/keyvalue_storage_read_request.cpp b/ydb/core/keyvalue/keyvalue_storage_read_request.cpp
index 7d463d8736b..d837e194370 100644
--- a/ydb/core/keyvalue/keyvalue_storage_read_request.cpp
+++ b/ydb/core/keyvalue/keyvalue_storage_read_request.cpp
@@ -8,13 +8,15 @@
namespace NKikimr {
namespace NKeyValue {
-#define STLOG_WITH_ERROR_DESCRIPTION(VARIABLE, PRIO, COMP, MARKER, TEXT, ...) \
+#define STLOG_WITH_ERROR_DESCRIPTION(VARIABLE, PRIO, COMP, ...) \
do { \
- struct MARKER {}; \
- VARIABLE = (TStringBuilder() << VARIABLE << Endl \
- << ::NKikimr::NStLog::TMessage<MARKER>(__FILE__, __LINE__, #MARKER, TStringBuilder() << TEXT) \
- STLOG_PARAMS(__VA_ARGS__)); \
- STLOG(PRIO, COMP, MARKER, TEXT, __VA_ARGS__); \
+ VARIABLE += "\n"; \
+ STLOG_STREAM(__stream, 0, __VA_ARGS__); \
+ const TString message = __stream.Str(); \
+ VARIABLE += message; \
+ const auto priority = [&]{ using namespace NActors::NLog; return (PRIO); }(); \
+ const auto component = [&]{ using namespace NKikimrServices; using namespace NActorsServices; return (COMP); }(); \
+ LOG_LOG_S(*TlsActivationContext, priority, component, message); \
} while(false) \
// STLOG_WITH_ERROR_DESCRIPTION
diff --git a/ydb/core/util/CMakeLists.txt b/ydb/core/util/CMakeLists.txt
index d473116dd5f..ba1c081f7db 100644
--- a/ydb/core/util/CMakeLists.txt
+++ b/ydb/core/util/CMakeLists.txt
@@ -19,6 +19,7 @@ target_link_libraries(ydb-core-util PUBLIC
cpp-containers-stack_vector
cpp-html-escape
library-cpp-ipmath
+ library-cpp-json
library-cpp-lwtrace
cpp-monlib-dynamic_counters
library-cpp-random_provider
@@ -41,6 +42,7 @@ target_sources(ydb-core-util PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/util/memory_tracker.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/page_map.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/single_thread_ic_mock.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/util/stlog.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/testactorsys.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/text.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/ulid.cpp
diff --git a/ydb/core/util/stlog.cpp b/ydb/core/util/stlog.cpp
new file mode 100644
index 00000000000..7c0cea61d18
--- /dev/null
+++ b/ydb/core/util/stlog.cpp
@@ -0,0 +1,17 @@
+#include "stlog.h"
+#include <library/cpp/json/json_reader.h>
+#include <google/protobuf/util/json_util.h>
+
+namespace NKikimr::NStLog {
+
+ void ProtobufToJson(const NProtoBuf::Message& m, NJson::TJsonWriter& json) {
+ TString s;
+ google::protobuf::util::MessageToJsonString(m, &s);
+ if (s) {
+ json.UnsafeWrite(s);
+ } else {
+ json.Write("protobuf deserialization error");
+ }
+ }
+
+} // NKikimr::NStLog
diff --git a/ydb/core/util/stlog.h b/ydb/core/util/stlog.h
index dfe8fa79502..c8b14bb4ea0 100644
--- a/ydb/core/util/stlog.h
+++ b/ydb/core/util/stlog.h
@@ -2,6 +2,7 @@
#include <ydb/core/protos/services.pb.h>
#include <library/cpp/actors/core/log.h>
+#include <library/cpp/json/json_writer.h>
#include <google/protobuf/text_format.h>
// special hack for gcc
@@ -9,6 +10,10 @@ static struct STLOG_PARAM_T {} STLOG_PARAM;
namespace NKikimr::NStLog {
+ static constexpr bool OutputLogJson = false;
+
+ void ProtobufToJson(const NProtoBuf::Message& m, NJson::TJsonWriter& json);
+
#define STLOG_EXPAND(X) X
#ifdef _MSC_VER
@@ -45,46 +50,37 @@ namespace NKikimr::NStLog {
#define STLOG_PARAMS_15(KV, ...) STLOG_PARAMS_1(KV) STLOG_EXPAND(STLOG_PARAMS_14(__VA_ARGS__))
#define STLOG_PARAMS_16(KV, ...) STLOG_PARAMS_1(KV) STLOG_EXPAND(STLOG_PARAMS_15(__VA_ARGS__))
-#define STLOGX(CTX, PRIO, COMP, MARKER, TEXT, ...) \
+#define STLOG_STREAM(NAME, JSON_OVERRIDE, MARKER, TEXT, ...) \
+ struct MARKER {}; \
+ TStringStream NAME; \
+ if constexpr (JSON_OVERRIDE ? JSON_OVERRIDE > 0 : ::NKikimr::NStLog::OutputLogJson) { \
+ NJson::TJsonWriter __json(&NAME, false); \
+ ::NKikimr::NStLog::TMessage<MARKER>(__FILE__, __LINE__, #MARKER)STLOG_PARAMS(__VA_ARGS__).WriteToJson(__json) << TEXT; \
+ } else { \
+ ::NKikimr::NStLog::TMessage<MARKER>(__FILE__, __LINE__, #MARKER)STLOG_PARAMS(__VA_ARGS__).WriteToStream(NAME) << TEXT; \
+ }
+
+#define STLOGX(CTX, PRIO, COMP, ...) \
do { \
- auto getPrio = [&] { using namespace NActors::NLog; return (PRIO); }; \
- auto getComp = [&] { using namespace NKikimrServices; using namespace NActorsServices; return (COMP); }; \
- auto makeMessage = [&] { \
- struct MARKER {}; \
- using Tag = MARKER; \
- return ::NKikimr::NStLog::TMessage<Tag>(__FILE__, __LINE__, #MARKER, TStringBuilder() << TEXT) \
- STLOG_PARAMS(__VA_ARGS__); \
+ auto& ctx = (CTX); \
+ const auto priority = [&]{ using namespace NActors::NLog; return (PRIO); }(); \
+ const auto component = [&]{ using namespace NKikimrServices; using namespace NActorsServices; return (COMP); }(); \
+ if (IS_LOG_PRIORITY_ENABLED(ctx, priority, component)) { \
+ STLOG_STREAM(__stream, 0, __VA_ARGS__); \
+ ::NActors::MemLogAdapter(ctx, priority, component, __stream.Str()); \
}; \
- LOG_LOG_S((CTX), getPrio(), getComp(), makeMessage()); \
} while (false)
-#define STLOG(PRIO, COMP, MARKER, TEXT, ...) \
- do { \
- if (TActivationContext *ctxp = TlsActivationContext) { \
- auto getPrio = [&] { using namespace NActors::NLog; return (PRIO); }; \
- auto getComp = [&] { using namespace NKikimrServices; using namespace NActorsServices; return (COMP); }; \
- auto makeMessage = [&] { \
- struct MARKER {}; \
- using Tag = MARKER; \
- return ::NKikimr::NStLog::TMessage<Tag>(__FILE__, __LINE__, #MARKER, TStringBuilder() << TEXT) \
- STLOG_PARAMS(__VA_ARGS__); \
- }; \
- LOG_LOG_S(*ctxp, getPrio(), getComp(), makeMessage()); \
- } \
- } while (false)
+#define STLOG(...) if (TActivationContext *ctxp = TlsActivationContext; !ctxp); else STLOGX(*ctxp, __VA_ARGS__)
-#define STLOG_DEBUG_FAIL(COMP, MARKER, TEXT, ...) \
+#define STLOG_DEBUG_FAIL(COMP, ...) \
do { \
if (TActivationContext *ctxp = TlsActivationContext) { \
- auto getComp = [&] { using namespace NKikimrServices; using namespace NActorsServices; return (COMP); }; \
- auto makeMessage = [&] { \
- struct MARKER {}; \
- using Tag = MARKER; \
- return ::NKikimr::NStLog::TMessage<Tag>(__FILE__, __LINE__, #MARKER, TStringBuilder() << TEXT) \
- STLOG_PARAMS(__VA_ARGS__); \
- }; \
- Y_VERIFY_DEBUG_S(false, makeMessage()); \
- LOG_LOG_S(*ctxp, NLog::PRI_CRIT, getComp(), makeMessage()); \
+ const auto component = [&]{ using namespace NKikimrServices; using namespace NActorsServices; return (COMP); }(); \
+ STLOG_STREAM(__stream, 0, __VA_ARGS__); \
+ const TString message = __stream.Str(); \
+ Y_VERIFY_DEBUG_S(false, message); \
+ LOG_LOG_S(*ctxp, NLog::PRI_CRIT, component, message); \
} \
} while (false)
@@ -118,32 +114,36 @@ namespace NKikimr::NStLog {
void WriteToStream(IOutputStream& s) const {
Base::WriteToStream(s);
- s << "# ";
- OutputParam(s, Value);
+ OutputParam(s << "# ", Value);
}
- private:
- template<typename TValue>
- static void OutputParam(IOutputStream& s, const std::optional<TValue>& value) {
- if (value) {
- OutputParam(s, *value);
- } else {
- s << "<null>";
- }
+ void WriteToJson(NJson::TJsonWriter& json) const {
+ Base::WriteToJson(json);
+ OutputParam(json, Value);
}
+ private:
+ template<typename Tx> struct TOptionalTraits { static constexpr bool HasOptionalValue = false; };
+ template<> struct TOptionalTraits<const char*> { static constexpr bool HasOptionalValue = false; };
+ template<> struct TOptionalTraits<char*> { static constexpr bool HasOptionalValue = false; };
+ template<typename Tx> struct TOptionalTraits<std::optional<Tx>> { static constexpr bool HasOptionalValue = true; };
+ template<typename Tx> struct TOptionalTraits<TMaybe<Tx>> { static constexpr bool HasOptionalValue = true; };
+ template<typename Tx> struct TOptionalTraits<Tx*> { static constexpr bool HasOptionalValue = true; };
+
template<typename TValue>
static void OutputParam(IOutputStream& s, const TValue& value) {
- if constexpr (google::protobuf::is_proto_enum<TValue>::value) {
- const google::protobuf::EnumDescriptor *e = google::protobuf::GetEnumDescriptor<TValue>();
+ using Tx = std::decay_t<TValue>;
+
+ if constexpr (google::protobuf::is_proto_enum<Tx>::value) {
+ const google::protobuf::EnumDescriptor *e = google::protobuf::GetEnumDescriptor<Tx>();
if (const auto *val = e->FindValueByNumber(value)) {
s << val->name();
} else {
s << static_cast<int>(value);
}
- } else if constexpr (std::is_same_v<TValue, bool>) {
+ } else if constexpr (std::is_same_v<Tx, bool>) {
s << (value ? "true" : "false");
- } else if constexpr (std::is_base_of_v<google::protobuf::Message, TValue>) {
+ } else if constexpr (std::is_base_of_v<google::protobuf::Message, Tx>) {
google::protobuf::TextFormat::Printer p;
p.SetSingleLineMode(true);
TString str;
@@ -152,15 +152,15 @@ namespace NKikimr::NStLog {
} else {
s << "<error>";
}
- } else if constexpr (THasToStringMethod<TValue>::value) {
+ } else if constexpr (THasToStringMethod<Tx>::value) {
s << value.ToString();
- } else if constexpr (std::is_pointer_v<TValue> && !std::is_same_v<std::remove_cv_t<std::remove_pointer_t<TValue>>, char>) {
+ } else if constexpr (TOptionalTraits<Tx>::HasOptionalValue) {
if (value) {
OutputParam(s, *value);
} else {
s << "<null>";
}
- } else if constexpr (TIsIterable<TValue>::value) {
+ } else if constexpr (TIsIterable<Tx>::value) {
auto begin = std::begin(value);
auto end = std::end(value);
bool first = true;
@@ -178,6 +178,35 @@ namespace NKikimr::NStLog {
s << value;
}
}
+
+ template<typename TValue>
+ static void OutputParam(NJson::TJsonWriter& json, const TValue& value) {
+ using Tx = std::decay_t<TValue>;
+
+ if constexpr (std::is_base_of_v<google::protobuf::Message, Tx>) {
+ ProtobufToJson(value, json);
+ } else if constexpr (TOptionalTraits<Tx>::HasOptionalValue) {
+ if (value) {
+ OutputParam(json, *value);
+ } else {
+ json.WriteNull();
+ }
+ } else if constexpr (TIsIterable<Tx>::value) {
+ json.OpenArray();
+ auto begin = std::begin(value);
+ auto end = std::end(value);
+ for (; begin != end; ++begin) {
+ OutputParam(json, *begin);
+ }
+ json.CloseArray();
+ } else if constexpr (std::is_constructible_v<NJson::TJsonValue, Tx>) {
+ json.Write(value);
+ } else {
+ TStringStream stream;
+ OutputParam(stream, value);
+ json.Write(stream.Str());
+ }
+ }
};
class TUnboundParam {
@@ -196,6 +225,10 @@ namespace NKikimr::NStLog {
void WriteToStream(IOutputStream& s) const {
s << Name;
}
+
+ void WriteToJson(NJson::TJsonWriter& json) const {
+ json.WriteKey(Name);
+ }
};
template<typename Tag, typename... TParams>
@@ -203,53 +236,120 @@ namespace NKikimr::NStLog {
const char *File;
int Line;
const char *Marker;
- TString Text;
std::tuple<TParams...> Params;
static constexpr size_t NumParams = sizeof...(TParams);
public:
template<typename... TArgs>
- TMessage(const char *file, int line, const char *marker, TString text, std::tuple<TParams...>&& params = {})
+ TMessage(const char *file, int line, const char *marker, std::tuple<TParams...>&& params = {})
: File(file)
, Line(line)
, Marker(marker)
- , Text(std::move(text))
, Params(std::move(params))
{}
template<typename Base, typename T>
TMessage<Tag, TParams..., TBoundParam<Base, T>> AppendBoundParam(TBoundParam<Base, T>&& p) {
- return {File, Line, Marker, std::move(Text), std::tuple_cat(Params, std::make_tuple(std::move(p)))};
+ return {File, Line, Marker, std::tuple_cat(Params, std::make_tuple(std::move(p)))};
}
TMessage<Tag, TParams...> AppendBoundParam(const STLOG_PARAM_T&) {
return std::move(*this);
}
- void WriteToStream(IOutputStream& s) const {
- const char *p = strrchr(File, '/');
- p = p ? p + 1 : File;
- s << "{" << Marker << "@" << p << ":" << Line << "} " << Text;
- WriteParams<0>(s, nullptr);
+ struct TStreamWriter {
+ const TMessage *Self;
+ IOutputStream& Stream;
+
+ template<typename T>
+ TStreamWriter& operator <<(const T& value) {
+ Stream << value;
+ return *this;
+ }
+
+ TStreamWriter(const TMessage *self, IOutputStream& stream)
+ : Self(self)
+ , Stream(stream)
+ {
+ Self->WriteHeaderToStream(Stream);
+ }
+
+ ~TStreamWriter() {
+ Self->WriteParamsToStream(Stream);
+ }
+ };
+
+ TStreamWriter WriteToStream(IOutputStream& s) const {
+ return {this, s};
+ }
+
+ struct TJsonWriter {
+ const TMessage *Self;
+ NJson::TJsonWriter& Json;
+ TStringStream Stream;
+
+ template<typename T>
+ TJsonWriter& operator <<(const T& value) {
+ Stream << value;
+ return *this;
+ }
+
+ TJsonWriter(const TMessage *self, NJson::TJsonWriter& json)
+ : Self(self)
+ , Json(json)
+ {}
+
+ ~TJsonWriter() {
+ Json.OpenMap();
+ Json.WriteKey("Marker");
+ Json.Write(Self->Marker);
+ Json.WriteKey("File");
+ Json.Write(Self->GetFileName());
+ Json.WriteKey("Line");
+ Json.Write(Self->Line);
+ Json.WriteKey("Text");
+ Json.Write(Stream.Str());
+ Self->WriteParamsToJson(Json);
+ Json.CloseMap();
+ }
+ };
+
+ TJsonWriter WriteToJson(NJson::TJsonWriter& json) const {
+ return {this, json};
}
private:
- template<size_t Index>
- void WriteParams(IOutputStream& s, std::enable_if_t<Index != NumParams>*) const {
- s << " ";
- std::get<Index>(Params).WriteToStream(s);
- WriteParams<Index + 1>(s, nullptr);
+ const char *GetFileName() const {
+ const char *p = strrchr(File, '/');
+ return p ? p + 1 : File;
+ }
+
+ void WriteHeaderToStream(IOutputStream& s) const {
+ s << "{" << Marker << "@" << GetFileName() << ":" << Line << "} ";
+ }
+
+ void WriteParamsToStream(IOutputStream& s) const {
+ WriteParams<0>(&s);
+ }
+
+ void WriteParamsToJson(NJson::TJsonWriter& json) const {
+ WriteParams<0>(&json);
+ }
+
+ template<size_t Index, typename = std::enable_if_t<Index != NumParams>>
+ void WriteParams(IOutputStream *s) const {
+ std::get<Index>(Params).WriteToStream(*s << " ");
+ WriteParams<Index + 1>(s);
+ }
+
+ template<size_t Index, typename = std::enable_if_t<Index != NumParams>>
+ void WriteParams(NJson::TJsonWriter *json) const {
+ std::get<Index>(Params).WriteToJson(*json);
+ WriteParams<Index + 1>(json);
}
- // out-of-range handler
template<size_t Index>
- void WriteParams(IOutputStream&, ...) const {}
+ void WriteParams(...) const {}
};
}
-
-template<typename Tag, typename... TParams>
-IOutputStream& operator <<(IOutputStream& s, const NKikimr::NStLog::TMessage<Tag, TParams...>& message) {
- message.WriteToStream(s);
- return s;
-}
diff --git a/ydb/core/util/stlog_ut.cpp b/ydb/core/util/stlog_ut.cpp
new file mode 100644
index 00000000000..be87e2116d7
--- /dev/null
+++ b/ydb/core/util/stlog_ut.cpp
@@ -0,0 +1,41 @@
+#include "stlog.h"
+#include <ydb/core/base/logoblob.h>
+#include <ydb/core/protos/base.pb.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(StLog) {
+
+ Y_UNIT_TEST(Basic) {
+ std::optional<int> x1(1);
+ std::optional<int> y1;
+ TMaybe<int> x2(2);
+ TMaybe<int> y2;
+ int z = 3;
+ const int *x3 = &z;
+ const int *y3 = nullptr;
+ std::vector<int> v{{1, 2, 3}};
+ NKikimrProto::EReplyStatus status = NKikimrProto::RACE;
+ NKikimrProto::TLogoBlobID id;
+ LogoBlobIDFromLogoBlobID(NKikimr::TLogoBlobID(1, 2, 3, 4, 5, 6), &id);
+ struct {
+ TString ToString() const { return "yep"; }
+ } s;
+ STLOG_STREAM(stream, -1, MARKER1, "hello, world", (Param1, 1), (Param2, 'c'), (Param3, 1.1f), (Param4, "abcdef"),
+ (Param5, TString("abcdef")), (Param6, x1), (Param7, x2), (Param8, x3), (Param9, y1),
+ (Param10, y2), (Param11, y3), (Param12, true), (Param13, v), (Param14, status), (Param15, id),
+ (Param16, &s));
+ UNIT_ASSERT_VALUES_EQUAL(stream.Str(), "{MARKER1@stlog_ut.cpp:26} hello, world Param1# 1 Param2# c Param3# 1.1 "
+ "Param4# abcdef Param5# abcdef Param6# 1 Param7# 2 Param8# 3 Param9# <null> Param10# <null> Param11# <null> "
+ "Param12# true Param13# [1 2 3] Param14# RACE Param15# {RawX1: 1 RawX2: 288230376185266176 "
+ "RawX3: 216172807883587664 } Param16# yep");
+ STLOG_STREAM(stream2, 1, MARKER2, "hello, world", (Param1, 1), (Param2, 'c'), (Param3, 1.1f), (Param4, "abcdef"),
+ (Param5, TString("abcdef")), (Param6, x1), (Param7, x2), (Param8, x3), (Param9, y1),
+ (Param10, y2), (Param11, y3), (Param12, true), (Param13, v), (Param14, status), (Param15, id),
+ (Param16, &s));
+ UNIT_ASSERT_VALUES_EQUAL(stream2.Str(), R"({"Marker":"MARKER2","File":"stlog_ut.cpp","Line":34,"Text":"hello, world",)"
+ R"("Param1":1,"Param2":99,"Param3":1.1,"Param4":"abcdef","Param5":"abcdef","Param6":1,"Param7":2,"Param8":3,)"
+ R"("Param9":null,"Param10":null,"Param11":null,"Param12":true,"Param13":[1,2,3],"Param14":4,"Param15":)"
+ R"({"RawX1":"1","RawX2":"288230376185266176","RawX3":"216172807883587664"},"Param16":"yep"})");
+ }
+
+}
diff --git a/ydb/core/util/ut/CMakeLists.darwin.txt b/ydb/core/util/ut/CMakeLists.darwin.txt
index 34fa381ca0f..84db9577ec1 100644
--- a/ydb/core/util/ut/CMakeLists.darwin.txt
+++ b/ydb/core/util/ut/CMakeLists.darwin.txt
@@ -54,6 +54,7 @@ target_sources(ydb-core-util-ut PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/util/queue_inplace_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/queue_oneone_inplace_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/simple_cache_ut.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/util/stlog_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/time_series_vec_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/token_bucket_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/ulid_ut.cpp
diff --git a/ydb/core/util/ut/CMakeLists.linux-aarch64.txt b/ydb/core/util/ut/CMakeLists.linux-aarch64.txt
index 175d4481ee4..2aad5d4954f 100644
--- a/ydb/core/util/ut/CMakeLists.linux-aarch64.txt
+++ b/ydb/core/util/ut/CMakeLists.linux-aarch64.txt
@@ -56,6 +56,7 @@ target_sources(ydb-core-util-ut PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/util/queue_inplace_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/queue_oneone_inplace_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/simple_cache_ut.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/util/stlog_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/time_series_vec_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/token_bucket_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/ulid_ut.cpp
diff --git a/ydb/core/util/ut/CMakeLists.linux.txt b/ydb/core/util/ut/CMakeLists.linux.txt
index 8e78674cd88..a8d9aff7933 100644
--- a/ydb/core/util/ut/CMakeLists.linux.txt
+++ b/ydb/core/util/ut/CMakeLists.linux.txt
@@ -58,6 +58,7 @@ target_sources(ydb-core-util-ut PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/util/queue_inplace_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/queue_oneone_inplace_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/simple_cache_ut.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/util/stlog_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/time_series_vec_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/token_bucket_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/util/ulid_ut.cpp