aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2018-03-10 14:08:15 +0100
committerWladimir J. van der Laan <laanwj@gmail.com>2018-03-10 17:15:00 +0100
commitbb98aec6743ee6cfde593a0bb30d5d1c43f8b0cb (patch)
treeb99b314c2166933c3a4e3843173e5cba9789555e
parent29fad97c320c892ab6a480c81e2078ec22ab354b (diff)
parenta7324bd799591546c2ae069f29cb82a66d427769 (diff)
Merge #12567: util: Print timestamp strings in logs using ISO 8601 formatting
a7324bd79 Format timestamps using ISO 8601 formatting (e.g. "2018-02-28T12:34:56Z") (practicalswift) Pull request description: Print timestamp strings in logs using [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatting (e.g. `2018-02-28T12:34:56Z`): * `Z` is the zone designator for the zero [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time) offset. * `T` is the delimiter used to separate date and time. This makes it clear for the end-user that the date/time logged is specified in UTC and not in the local time zone. Before this patch: ``` 2018-02-28 12:34:56 New outbound peer connected: version: 70015, blocks=1286123, peer=0 ``` After this patch: ``` 2018-02-28T12:34:56Z New outbound peer connected: version: 70015, blocks=1286123, peer=0 ``` Tree-SHA512: 52b53c3d3d11ddf4af521a3b5f90a79f6e6539ee5955ec56a5aa2c6a5cf29cecf166d8cb43277c62553c3325a31bcea83691acbb4e86429c523f8aff8d7b210a
-rw-r--r--doc/release-notes.md4
-rw-r--r--src/init.cpp2
-rw-r--r--src/net.cpp2
-rw-r--r--src/qt/paymentserver.cpp2
-rw-r--r--src/test/util_tests.cpp17
-rw-r--r--src/util.cpp10
-rw-r--r--src/utiltime.cpp12
-rw-r--r--src/utiltime.h8
-rw-r--r--src/validation.cpp11
-rw-r--r--src/wallet/rpcdump.cpp12
-rwxr-xr-xtest/functional/combine_logs.py2
-rwxr-xr-xtest/functional/test_framework/test_framework.py2
12 files changed, 61 insertions, 23 deletions
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 8fcd2a9163..d08e2518c7 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -93,6 +93,10 @@ Low-level RPC changes
with any `-wallet=<path>` options, there is no change in behavior, and the
name of any wallet is just its `<path>` string.
+### Logging
+
+- The log timestamp format is now ISO 8601 (e.g. "2018-02-28T12:34:56Z").
+
Credits
=======
diff --git a/src/init.cpp b/src/init.cpp
index 659f97fec6..bc23d0ff83 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1224,7 +1224,7 @@ bool AppInitMain()
}
if (!fLogTimestamps)
- LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()));
+ LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime()));
LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
LogPrintf("Using data directory %s\n", GetDataDir().string());
LogPrintf("Using config file %s\n", GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string());
diff --git a/src/net.cpp b/src/net.cpp
index 33a60ac96e..53a0a9b180 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2795,7 +2795,7 @@ void CNode::AskFor(const CInv& inv)
nRequestTime = it->second;
else
nRequestTime = 0;
- LogPrint(BCLog::NET, "askfor %s %d (%s) peer=%d\n", inv.ToString(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000), id);
+ LogPrint(BCLog::NET, "askfor %s %d (%s) peer=%d\n", inv.ToString(), nRequestTime, FormatISO8601Time(nRequestTime/1000000), id);
// Make sure not to reuse time indexes to keep things in the same order
int64_t nNow = GetTimeMicros() - 1000000;
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 8ad4fa31f1..4b6fdc8d57 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -770,7 +770,7 @@ bool PaymentServer::verifyExpired(const payments::PaymentDetails& requestDetails
{
bool fVerified = (requestDetails.has_expires() && (int64_t)requestDetails.expires() < GetTime());
if (fVerified) {
- const QString requestExpires = QString::fromStdString(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", (int64_t)requestDetails.expires()));
+ const QString requestExpires = QString::fromStdString(FormatISO8601DateTime((int64_t)requestDetails.expires()));
qWarning() << QString("PaymentServer::%1: Payment request expired \"%2\".")
.arg(__func__)
.arg(requestExpires);
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 58f033cd89..84b61bea86 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -164,10 +164,27 @@ BOOST_AUTO_TEST_CASE(util_DateTimeStrFormat)
BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 0), "1970-01-01 00:00:00");
BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 0x7FFFFFFF), "2038-01-19 03:14:07");
BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 1317425777), "2011-09-30 23:36:17");
+ BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", 1317425777), "2011-09-30T23:36:17Z");
+ BOOST_CHECK_EQUAL(DateTimeStrFormat("%H:%M:%SZ", 1317425777), "23:36:17Z");
BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M", 1317425777), "2011-09-30 23:36");
BOOST_CHECK_EQUAL(DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", 1317425777), "Fri, 30 Sep 2011 23:36:17 +0000");
}
+BOOST_AUTO_TEST_CASE(util_FormatISO8601DateTime)
+{
+ BOOST_CHECK_EQUAL(FormatISO8601DateTime(1317425777), "2011-09-30T23:36:17Z");
+}
+
+BOOST_AUTO_TEST_CASE(util_FormatISO8601Date)
+{
+ BOOST_CHECK_EQUAL(FormatISO8601Date(1317425777), "2011-09-30");
+}
+
+BOOST_AUTO_TEST_CASE(util_FormatISO8601Time)
+{
+ BOOST_CHECK_EQUAL(FormatISO8601Time(1317425777), "23:36:17Z");
+}
+
class TestArgsManager : public ArgsManager
{
public:
diff --git a/src/util.cpp b/src/util.cpp
index 82c99a3c2f..62cdce3012 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -315,12 +315,14 @@ static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fSt
if (*fStartedNewLine) {
int64_t nTimeMicros = GetTimeMicros();
- strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTimeMicros/1000000);
- if (fLogTimeMicros)
- strStamped += strprintf(".%06d", nTimeMicros%1000000);
+ strStamped = FormatISO8601DateTime(nTimeMicros/1000000);
+ if (fLogTimeMicros) {
+ strStamped.pop_back();
+ strStamped += strprintf(".%06dZ", nTimeMicros%1000000);
+ }
int64_t mocktime = GetMockTime();
if (mocktime) {
- strStamped += " (mocktime: " + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", mocktime) + ")";
+ strStamped += " (mocktime: " + FormatISO8601DateTime(mocktime) + ")";
}
strStamped += ' ' + str;
} else
diff --git a/src/utiltime.cpp b/src/utiltime.cpp
index e908173135..8a861039b3 100644
--- a/src/utiltime.cpp
+++ b/src/utiltime.cpp
@@ -85,3 +85,15 @@ std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime)
ss << boost::posix_time::from_time_t(nTime);
return ss.str();
}
+
+std::string FormatISO8601DateTime(int64_t nTime) {
+ return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
+}
+
+std::string FormatISO8601Date(int64_t nTime) {
+ return DateTimeStrFormat("%Y-%m-%d", nTime);
+}
+
+std::string FormatISO8601Time(int64_t nTime) {
+ return DateTimeStrFormat("%H:%M:%SZ", nTime);
+}
diff --git a/src/utiltime.h b/src/utiltime.h
index 56cc31da67..807c52ffaf 100644
--- a/src/utiltime.h
+++ b/src/utiltime.h
@@ -27,6 +27,14 @@ void SetMockTime(int64_t nMockTimeIn);
int64_t GetMockTime();
void MilliSleep(int64_t n);
+/**
+ * ISO 8601 formatting is preferred. Use the FormatISO8601{DateTime,Date,Time}
+ * helper functions if possible.
+ */
std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime);
+std::string FormatISO8601DateTime(int64_t nTime);
+std::string FormatISO8601Date(int64_t nTime);
+std::string FormatISO8601Time(int64_t nTime);
+
#endif // BITCOIN_UTILTIME_H
diff --git a/src/validation.cpp b/src/validation.cpp
index 51e40c17b5..c677f44b3e 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1267,13 +1267,12 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
LogPrintf("%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", __func__,
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight,
- log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S",
- pindexNew->GetBlockTime()));
+ log(pindexNew->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(pindexNew->GetBlockTime()));
CBlockIndex *tip = chainActive.Tip();
assert (tip);
LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__,
tip->GetBlockHash().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0),
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", tip->GetBlockTime()));
+ FormatISO8601DateTime(tip->GetBlockTime()));
CheckForkWarningConditions();
}
@@ -2229,7 +2228,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar
LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)", __func__,
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion,
log(pindexNew->nChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx,
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexNew->GetBlockTime()),
+ FormatISO8601DateTime(pindexNew->GetBlockTime()),
GuessVerificationProgress(chainParams.TxData(), pindexNew), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
if (!warningMessages.empty())
LogPrintf(" warning='%s'", boost::algorithm::join(warningMessages, ", "));
@@ -3856,7 +3855,7 @@ bool LoadChainTip(const CChainParams& chainparams)
LogPrintf("Loaded best chain: hashBestChain=%s height=%d date=%s progress=%f\n",
chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(),
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
+ FormatISO8601DateTime(chainActive.Tip()->GetBlockTime()),
GuessVerificationProgress(chainparams.TxData(), chainActive.Tip()));
return true;
}
@@ -4554,7 +4553,7 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
std::string CBlockFileInfo::ToString() const
{
- return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast));
+ return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, FormatISO8601Date(nTimeFirst), FormatISO8601Date(nTimeLast));
}
CBlockFileInfo* GetBlockFileInfo(size_t n)
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 0edc8d8d66..c7c54ecb9b 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -28,10 +28,6 @@
#include <univalue.h>
-std::string static EncodeDumpTime(int64_t nTime) {
- return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
-}
-
int64_t static DecodeDumpTime(const std::string &str) {
static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0);
static const std::locale loc(std::locale::classic(),
@@ -722,9 +718,9 @@ UniValue dumpwallet(const JSONRPCRequest& request)
// produce output
file << strprintf("# Wallet dump created by Bitcoin %s\n", CLIENT_BUILD);
- file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()));
+ file << strprintf("# * Created on %s\n", FormatISO8601DateTime(GetTime()));
file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString());
- file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime()));
+ file << strprintf("# mined on %s\n", FormatISO8601DateTime(chainActive.Tip()->GetBlockTime()));
file << "\n";
// add the base58check encoded extended master if the wallet uses HD
@@ -741,7 +737,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
}
for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
const CKeyID &keyid = it->second;
- std::string strTime = EncodeDumpTime(it->first);
+ std::string strTime = FormatISO8601DateTime(it->first);
std::string strAddr;
std::string strLabel;
CKey key;
@@ -769,7 +765,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
// get birth times for scripts with metadata
auto it = pwallet->m_script_metadata.find(scriptid);
if (it != pwallet->m_script_metadata.end()) {
- create_time = EncodeDumpTime(it->second.nCreateTime);
+ create_time = FormatISO8601DateTime(it->second.nCreateTime);
}
if(pwallet->GetCScript(scriptid, script)) {
file << strprintf("%s %s script=1", HexStr(script.begin(), script.end()), create_time);
diff --git a/test/functional/combine_logs.py b/test/functional/combine_logs.py
index 3ca74ea35e..d1bf9206b2 100755
--- a/test/functional/combine_logs.py
+++ b/test/functional/combine_logs.py
@@ -13,7 +13,7 @@ import re
import sys
# Matches on the date format at the start of the log event
-TIMESTAMP_PATTERN = re.compile(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{6}")
+TIMESTAMP_PATTERN = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z")
LogEvent = namedtuple('LogEvent', ['timestamp', 'source', 'event'])
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 86c1150abd..f4e77d32dc 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -358,7 +358,7 @@ class BitcoinTestFramework():
ll = int(self.options.loglevel) if self.options.loglevel.isdigit() else self.options.loglevel.upper()
ch.setLevel(ll)
# Format logs the same as bitcoind's debug.log with microprecision (so log files can be concatenated and sorted)
- formatter = logging.Formatter(fmt='%(asctime)s.%(msecs)03d000 %(name)s (%(levelname)s): %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
+ formatter = logging.Formatter(fmt='%(asctime)s.%(msecs)03d000Z %(name)s (%(levelname)s): %(message)s', datefmt='%Y-%m-%dT%H:%M:%S')
formatter.converter = time.gmtime
fh.setFormatter(formatter)
ch.setFormatter(formatter)