*this << ca.toLogString();
return *this;
}
+
+#ifdef RECURSOR
+void addTraceTS(const timeval& start, ostringstream& str)
+{
+ const auto & content = str.str();
+ if (content.empty() || content.at(content.size() - 1) == '\n') {
+ timeval time{};
+ gettimeofday(&time, nullptr);
+ auto elapsed = time - start;
+ auto diff = elapsed.tv_sec * 1000000 + static_cast<time_t>(elapsed.tv_usec);
+ str << diff << ' ';
+ }
+}
+#endif
struct LogVariant
{
string prefix;
+ timeval start;
// variant cannot hold references
std::variant<Logger*, ostringstream*> v;
};
using OptLog = std::optional<LogVariant>;
+
#ifndef RECURSOR
// Originally there was a flag but it was never set from !RECURSOR
#define VLOG(log, x) VLOG only works in recursor
#else
-#define VLOG(log, x) \
- if (log) { \
- if (std::holds_alternative<Logger*>((log)->v)) { \
+
+void addTraceTS(const timeval& start, ostringstream& str);
+
+#define VLOG(log, x) \
+ if (log) { \
+ if (std::holds_alternative<Logger*>((log)->v)) { \
*std::get<Logger*>(log->v) << Logger::Warning << (log)->prefix << x; \
- } \
- else if (std::holds_alternative<ostringstream*>((log)->v)) { \
- *std::get<ostringstream*>((log)->v) << (log)->prefix << x; \
- } \
+ } \
+ else if (std::holds_alternative<ostringstream*>((log)->v)) { \
+ addTraceTS((log)->start, *std::get<ostringstream*>((log)->v)); \
+ *std::get<ostringstream*>((log)->v) << (log)->prefix << x; \
+ } \
}
#endif
}
#endif // HAVE_FSTRM
-static void dumpTrace(const string& trace)
+const char* timestamp(const struct timeval& tv, char* buf, size_t sz);
+
+static void dumpTrace(const string& trace, const timeval& timev)
{
if (trace.empty()) {
return;
}
+ timeval now{};
+ Utility::gettimeofday(&now);
int traceFd = dup(t_tracefd);
if (traceFd == -1) {
int err = errno;
close(traceFd);
return;
}
- vector<string> lines;
- boost::split(lines, trace, boost::is_any_of("\n"));
- int count = 0;
- for (const string& line : lines) {
- if (!line.empty())
- fprintf(filep.get(), "%04d %s\n", ++count, line.c_str());
- }
- fprintf(filep.get(), "\n");
+ std::array<char, 64> timebuf;
+ timestamp(timev, timebuf.data(), timebuf.size());
+ fprintf(filep.get(), " us === START OF TRACE %s ===\n", timebuf.data());
+ fprintf(filep.get(), "%s", trace.c_str());
+ timestamp(now, timebuf.data(), timebuf.size());
+ fprintf(filep.get(), "=== END OF TRACE %s ===\n", timebuf.data());
// fclose by unique_ptr does implicit flush
}
if (t_traceRegex && t_traceRegex->match(dc->d_mdp.d_qname.toString())) {
sr.setLogMode(SyncRes::Store);
tracedQuery = true;
- sr.setId("T");
}
if (!g_quiet || tracedQuery) {
haveAnswer:;
if (tracedQuery || res == -1 || res == RCode::ServFail || pw.getHeader()->rcode == RCode::ServFail) {
- dumpTrace(sr.getTrace());
+ dumpTrace(sr.getTrace(), sr.d_fixednow);
}
if (res == -1) {
unsigned int SyncRes::s_max_busy_dot_probes;
bool SyncRes::s_addExtendedResolutionDNSErrors;
-#define LOG(x) \
- if (d_lm == Log) { \
- g_log << Logger::Warning << x; \
- } \
- else if (d_lm == Store) { \
- d_trace << x; \
+#define LOG(x) \
+ if (d_lm == Log) { \
+ g_log << Logger::Warning << x; \
+ } \
+ else if (d_lm == Store) { \
+ addTraceTS(d_fixednow, d_trace); \
+ d_trace << x; \
}
OptLog SyncRes::LogObject(const string& prefix)
{
OptLog ret;
if (d_lm == Log) {
- ret = {prefix, &g_log};
+ ret = {prefix, d_fixednow, &g_log};
}
else if (d_lm == Store) {
- ret = {prefix, &d_trace};
+ ret = {prefix, d_now, &d_trace};
}
return ret;
}
}
SyncRes::SyncRes(const struct timeval& now) :
- d_authzonequeries(0), d_outqueries(0), d_tcpoutqueries(0), d_dotoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0), d_totUsec(0), d_now(now), d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_qNameMinimization(s_qnameminimization), d_lm(s_lm)
+ d_authzonequeries(0), d_outqueries(0), d_tcpoutqueries(0), d_dotoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0), d_totUsec(0), d_fixednow(now), d_now(now), d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_qNameMinimization(s_qnameminimization), d_lm(s_lm)
+
{
}
return iter != t_sstorage.domainmap->end();
}
-// Will be needed in the future
-static const char* timestamp(const struct timeval& tv, char* buf, size_t sz)
+const char* timestamp(const struct timeval& tv, char* buf, size_t sz)
{
const std::string s_timestampFormat = "%Y-%m-%dT%T";
struct tm tm;
unsigned int d_timeouts;
unsigned int d_unreachables;
unsigned int d_totUsec;
+ const struct timeval d_fixednow;
private:
ComboAddress d_requestor;