blob: cb102269288c850dd73ea33d9dadfdf9352f0b09 [file] [log] [blame]
// 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 <glog/logging.h>
#include <gtest/gtest.h>
#include <rapidjson/document.h>
#include <rapidjson/rapidjson.h>
#include <cctype>
#include <cstdint>
#include <cstring>
#include <functional>
#include <map>
#include <ostream>
#include <string>
#include <thread>
#include <vector>
#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 std::string XOutDigits(const string& s) {
std::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<Trace> t(new Trace);
TRACE_TO(t, "hello $0, $1", "world", 12345);
TRACE_TO(t, "goodbye $0, $1", "cruel world", 54321);
std::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<Trace> traceA(new Trace);
scoped_refptr<Trace> 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<Trace> traceA(new Trace);
scoped_refptr<Trace> 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> 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();
}