// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you 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 "util/trace.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gutil/macros.h" #include "gutil/port.h" #include "gutil/ref_counted.h" #include "gutil/walltime.h" #include "util/countdown_latch.h" #include "util/monotime.h" #include "util/scoped_cleanup.h" #include "util/stopwatch.hpp" #include "util/thread.h" #include "util/trace_metrics.h" using rapidjson::Document; using rapidjson::Value; using std::string; using std::thread; using std::vector; namespace doris { class TraceTest : public ::testing::Test { }; // Replace all digits in 's' with the character 'X'. static string XOutDigits(const string& s) { string ret; ret.reserve(s.size()); for (char c : s) { if (isdigit(c)) { ret.push_back('X'); } else { ret.push_back(c); } } return ret; } TEST_F(TraceTest, TestBasic) { scoped_refptr t(new Trace); TRACE_TO(t, "hello $0, $1", "world", 12345); TRACE_TO(t, "goodbye $0, $1", "cruel world", 54321); string result = XOutDigits(t->DumpToString(Trace::NO_FLAGS)); ASSERT_EQ("XXXX XX:XX:XX.XXXXXX trace_test.cpp:XX] hello world, XXXXX\n" "XXXX XX:XX:XX.XXXXXX trace_test.cpp:XX] goodbye cruel world, XXXXX\n", result); } TEST_F(TraceTest, TestAttach) { scoped_refptr traceA(new Trace); scoped_refptr traceB(new Trace); { ADOPT_TRACE(traceA.get()); EXPECT_EQ(traceA.get(), Trace::CurrentTrace()); { ADOPT_TRACE(traceB.get()); EXPECT_EQ(traceB.get(), Trace::CurrentTrace()); TRACE("hello from traceB"); } EXPECT_EQ(traceA.get(), Trace::CurrentTrace()); TRACE("hello from traceA"); } EXPECT_TRUE(Trace::CurrentTrace() == nullptr); TRACE("this goes nowhere"); EXPECT_EQ("XXXX XX:XX:XX.XXXXXX trace_test.cpp:XX] hello from traceA\n", XOutDigits(traceA->DumpToString(Trace::NO_FLAGS))); EXPECT_EQ("XXXX XX:XX:XX.XXXXXX trace_test.cpp:XX] hello from traceB\n", XOutDigits(traceB->DumpToString(Trace::NO_FLAGS))); } TEST_F(TraceTest, TestChildTrace) { scoped_refptr traceA(new Trace); scoped_refptr traceB(new Trace); ADOPT_TRACE(traceA.get()); traceA->AddChildTrace("child", traceB.get()); TRACE("hello from traceA"); { ADOPT_TRACE(traceB.get()); TRACE("hello from traceB"); } EXPECT_EQ("XXXX XX:XX:XX.XXXXXX trace_test.cpp:XXX] hello from traceA\n" "Related trace 'child':\n" "XXXX XX:XX:XX.XXXXXX trace_test.cpp:XXX] hello from traceB\n", XOutDigits(traceA->DumpToString(Trace::NO_FLAGS))); } TEST_F(TraceTest, TestTraceMetrics) { scoped_refptr trace(new Trace); trace->metrics()->Increment("foo", 10); trace->metrics()->Increment("bar", 10); for (int i = 0; i < 1000; i++) { trace->metrics()->Increment("baz", i); } EXPECT_EQ("{\"bar\":10,\"baz\":499500,\"foo\":10}", trace->MetricsAsJSON()); { ADOPT_TRACE(trace.get()); TRACE_COUNTER_SCOPE_LATENCY_US("test_scope_us"); SleepFor(MonoDelta::FromMilliseconds(100)); } auto m = trace->metrics()->Get(); EXPECT_GE(m["test_scope_us"], 80 * 1000); } } // namespace doris int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }