diff --git a/doc/release-notes.md b/doc/release-notes.md --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -28,3 +28,6 @@ - Added the `datadir` option to the seeder allowing a directory to be specified for the files the seeder writes to and reads from (default is the `~/.bitcoin/seeder` directory). See help for more details. +- The seeder will now log some of its debug and output strings to a + `seederdebug.log` file. The location of this file is defined by the + `-datadir` option. diff --git a/src/seeder/main.cpp b/src/seeder/main.cpp --- a/src/seeder/main.cpp +++ b/src/seeder/main.cpp @@ -112,14 +112,13 @@ // Warn about relative -datadir path if (gArgs.IsArgSet("-datadir") && !fs::path(gArgs.GetArg("-datadir", "")).is_absolute()) { - tfm::format( - std::cout, - "Warning: relative datadir option '%s' specified, which will " - "be interpreted relative to the current working directory " - "'%s'. This is fragile, because if the seeder is started in " - "the future from a different location, it will be unable to " - "locate the current data files.\n", - gArgs.GetArg("-datadir", ""), fs::current_path().string()); + LogPrintf("Warning: relative datadir option '%s' specified, which " + "will be interpreted relative to the current working " + "directory '%s'. This is fragile, because if the seeder " + "is started in the future from a different location, it " + "will be unable to locate the current data files.\n", + gArgs.GetArg("-datadir", ""), + fs::current_path().string()); } if (gArgs.IsArgSet("-filter")) { @@ -186,6 +185,14 @@ "-datadir=", "Specifies the directory that the seeder reads from and writes to.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + gArgs.AddArg("-printtoconsole", + "Send trace/debug info to console (default: 1)", + ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + gArgs.AddArg( + "-logtofile", + "Write trace/debug info to seederdebug.log file. This option does " + "not affect database files (default: 0)", + ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); SetupChainParamsBaseOptions(); gArgs.AddArg("-help", "", ArgsManager::ALLOW_ANY, @@ -509,9 +516,6 @@ } int main(int argc, char **argv) { - // The logger dump everything on the console by default. - LogInstance().m_print_to_console = true; - signal(SIGPIPE, SIG_IGN); setbuf(stdout, nullptr); CDnsSeedOpts opts; @@ -520,88 +524,104 @@ return parseResults; } - tfm::format(std::cout, "Supporting whitelisted filters: "); + // Set up logger + BCLog::Logger &logger = LogInstance(); + logger.m_print_to_console = gArgs.GetBoolArg("-printtoconsole", true); + logger.m_print_to_file = gArgs.GetBoolArg("-logtofile", false); + logger.m_file_path = AbsPathForConfigVal(GetDataDir() / "seederdebug.log"); + logger.m_log_timestamps = DEFAULT_LOGTIMESTAMPS; + logger.m_log_time_micros = DEFAULT_LOGTIMEMICROS; + logger.m_log_threadnames = DEFAULT_LOGTHREADNAMES; + if (!logger.StartLogging()) { + tfm::format(std::cout, "Could not open debug log file %s\n", + logger.m_file_path.string()); + tfm::format(std::cout, "Logging only to console\n"); + logger.m_print_to_file = false; + } + if (!logger.m_log_timestamps) { + LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime())); + } + LogPrintf("%s Seeder version %s\n", PACKAGE_NAME, FormatFullVersion()); + + LogPrintfToBeContinued("Supporting whitelisted filters: "); for (std::set::const_iterator it = opts.filter_whitelist.begin(); it != opts.filter_whitelist.end(); it++) { if (it != opts.filter_whitelist.begin()) { - tfm::format(std::cout, ","); + LogPrintfToBeContinued(","); } - tfm::format(std::cout, "0x%lx", (unsigned long)*it); + LogPrintfToBeContinued("0x%lx", (unsigned long)*it); } - tfm::format(std::cout, "\n"); + LogPrintf("\n"); if (!opts.tor.empty()) { CService service(LookupNumeric(opts.tor.c_str(), 9050)); if (service.IsValid()) { - tfm::format(std::cout, "Using Tor proxy at %s\n", - service.ToStringIPPort()); + LogPrintf("Using Tor proxy at %s\n", service.ToStringIPPort()); SetProxy(NET_ONION, proxyType(service)); } } if (!opts.ipv4_proxy.empty()) { CService service(LookupNumeric(opts.ipv4_proxy.c_str(), 9050)); if (service.IsValid()) { - tfm::format(std::cout, "Using IPv4 proxy at %s\n", - service.ToStringIPPort()); + LogPrintf("Using IPv4 proxy at %s\n", service.ToStringIPPort()); SetProxy(NET_IPV4, proxyType(service)); } } if (!opts.ipv6_proxy.empty()) { CService service(LookupNumeric(opts.ipv6_proxy.c_str(), 9050)); if (service.IsValid()) { - tfm::format(std::cout, "Using IPv6 proxy at %s\n", - service.ToStringIPPort()); + LogPrintf("Using IPv6 proxy at %s\n", service.ToStringIPPort()); SetProxy(NET_IPV6, proxyType(service)); } } bool fDNS = true; - tfm::format(std::cout, "Using %s.\n", gArgs.GetChainName()); + LogPrintf("Using %s.\n", gArgs.GetChainName()); netMagic = Params().NetMagic(); if (opts.ns.empty()) { - tfm::format(std::cout, "No nameserver set. Not starting DNS server.\n"); + LogPrintf("No nameserver set. Not starting DNS server.\n"); fDNS = false; } if (fDNS && opts.host.empty()) { - tfm::format(std::cerr, "No hostname set. Please use -h.\n"); + LogPrintf("No hostname set. Please use -h.\n"); return EXIT_FAILURE; } if (fDNS && opts.mbox.empty()) { - tfm::format(std::cerr, "No e-mail address set. Please use -m.\n"); + LogPrintf("No e-mail address set. Please use -m.\n"); return EXIT_FAILURE; } FILE *f = fsbridge::fopen(GetDataDir() / "dnsseed.dat", "r"); if (f) { - tfm::format(std::cout, "Loading dnsseed.dat..."); + LogPrintfToBeContinued("Loading dnsseed.dat..."); CAutoFile cf(f, SER_DISK, CLIENT_VERSION); cf >> db; if (opts.fWipeBan) { db.banned.clear(); - tfm::format(std::cout, "Ban list wiped..."); + LogPrintfToBeContinued("Ban list wiped..."); } if (opts.fWipeIgnore) { db.ResetIgnores(); - tfm::format(std::cout, "Ignore list wiped..."); + LogPrintfToBeContinued("Ignore list wiped..."); } - tfm::format(std::cout, "done\n"); + LogPrintf("done\n"); } pthread_t threadDns, threadSeed, threadDump, threadStats; if (fDNS) { - tfm::format(std::cout, - "Starting %i DNS threads for %s on %s (port %i)...", - opts.nDnsThreads, opts.host, opts.ns, opts.nPort); + LogPrintfToBeContinued( + "Starting %i DNS threads for %s on %s (port %i)...", + opts.nDnsThreads, opts.host, opts.ns, opts.nPort); dnsThread.clear(); for (int i = 0; i < opts.nDnsThreads; i++) { dnsThread.push_back(new CDnsThread(&opts, i)); pthread_create(&threadDns, nullptr, ThreadDNS, dnsThread[i]); - tfm::format(std::cout, "."); + LogPrintfToBeContinued("."); Sleep(20); } - tfm::format(std::cout, "done\n"); + LogPrintf("done\n"); } - tfm::format(std::cout, "Starting seeder..."); + LogPrintfToBeContinued("Starting seeder..."); pthread_create(&threadSeed, nullptr, ThreadSeeder, nullptr); - tfm::format(std::cout, "done\n"); - tfm::format(std::cout, "Starting %i crawler threads...", opts.nThreads); + LogPrintf("done\n"); + LogPrintfToBeContinued("Starting %i crawler threads...", opts.nThreads); pthread_attr_t attr_crawler; pthread_attr_init(&attr_crawler); pthread_attr_setstacksize(&attr_crawler, 0x20000); @@ -610,7 +630,7 @@ pthread_create(&thread, &attr_crawler, ThreadCrawler, &opts.nThreads); } pthread_attr_destroy(&attr_crawler); - tfm::format(std::cout, "done\n"); + LogPrintf("done\n"); pthread_create(&threadStats, nullptr, ThreadStats, nullptr); pthread_create(&threadDump, nullptr, ThreadDumper, nullptr); void *res;