diff --git a/doc/release-notes.md b/doc/release-notes.md --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -9,3 +9,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` and `-debuglogfile` options. See help for more details. diff --git a/src/seeder/main.cpp b/src/seeder/main.cpp --- a/src/seeder/main.cpp +++ b/src/seeder/main.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ static const std::string DEFAULT_TOR_PROXY = ""; static const std::string DEFAULT_IPV4_PROXY = ""; static const std::string DEFAULT_IPV6_PROXY = ""; +static const std::string DEFAULT_SEEDER_DEBUGLOGFILE = "seederdebug.log"; class CDnsSeedOpts { public: @@ -112,19 +114,17 @@ // 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()); } - tfm::format(std::cout, "Default data directory %s\n", - GetDefaultDataDir().string() + "/seeder"); - tfm::format(std::cout, "Using data directory %s\n", - GetDataDir().string()); + LogPrintf("Default data directory %s\n", + GetDefaultDataDir().string() + "/seeder"); + LogPrintf("Using data directory %s\n", GetDataDir().string()); if (gArgs.IsArgSet("-filter")) { // Parse whitelist additions @@ -190,6 +190,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("-debuglogfile=", + "Specify location of debug log file. Relative paths will " + "be prefixed by a net-specific datadir location. (0 to " + "disbale; default: seederdebug.log)", + ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); SetupChainParamsBaseOptions(); gArgs.AddArg("-help", "", ArgsManager::ALLOW_ANY, @@ -513,9 +521,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; @@ -524,88 +529,102 @@ 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.IsArgNegated("-debuglogfile"); + logger.m_file_path = AbsPathForConfigVal( + gArgs.GetArg("-debuglogfile", DEFAULT_SEEDER_DEBUGLOGFILE)); + if (!logger.StartLogging()) { + logger.m_print_to_file = false; + 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"); + } + if (!logger.m_log_timestamps) { + LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime())); + } + LogPrintf(PACKAGE_NAME " Seeder version %s\n", 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); @@ -614,7 +633,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;