// ACCESSORS void RecordStringFormatter::operator()(bsl::ostream& stream, const Record& record) const { const RecordAttributes& fixedFields = record.fixedFields(); bdlt::Datetime timestamp = fixedFields.timestamp(); if (k_ENABLE_PUBLISH_IN_LOCALTIME == d_timestampOffset.totalMilliseconds()) { int localTimeOffsetInSeconds = bdlt::LocalTimeOffset::localTimeOffset(timestamp).totalSeconds(); timestamp.addSeconds(localTimeOffsetInSeconds); } else if(k_DISABLE_PUBLISH_IN_LOCALTIME == d_timestampOffset.totalMilliseconds()) { // Do not adjust 'timestamp'. } else { timestamp += d_timestampOffset; } // Step through the format string, outputting the required elements. const char* iter = d_formatSpec.data(); const char* end = iter + d_formatSpec.length(); // Create a buffer on the stack for formatting the record. Note that the // size of the buffer should be slightly larger than the amount we reserve // in order to ensure only a single allocation occurs. const int BUFFER_SIZE = 512; const int STRING_RESERVATION = BUFFER_SIZE - bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT; char fixedBuffer[BUFFER_SIZE]; bdlma::BufferedSequentialAllocator stringAllocator(fixedBuffer, BUFFER_SIZE); bsl::string output(&stringAllocator); output.reserve(STRING_RESERVATION); #if defined(BSLS_PLATFORM_CMP_MSVC) #define snprintf _snprintf #endif while (iter != end) { switch (*iter) { case '%': { if (++iter == end) { break; } switch (*iter) { case '%': { output += '%'; } break; case 'd': { char buffer[32]; timestamp.printToBuffer(buffer, sizeof buffer); output += buffer; } break; case 'I': // fall through intentionally case 'i': { // use ISO8601 "extended" format char buffer[32]; snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d", timestamp.year(), timestamp.month(), timestamp.day(), timestamp.hour(), timestamp.minute(), timestamp.second()); output += buffer; if ('I' == *iter) { snprintf(buffer, sizeof(buffer), ".%03d", timestamp.millisecond()); output += buffer; } if (0 == d_timestampOffset.totalMilliseconds()) { output += 'Z'; } } break; case 'p': { appendToString(&output, fixedFields.processID()); } break; case 't': { appendToString(&output, fixedFields.threadID()); } break; case 's': { output += Severity::toAscii( (Severity::Level)fixedFields.severity()); } break; case 'f': { output += fixedFields.fileName(); } break; case 'F': { const bsl::string& filename = fixedFields.fileName(); bsl::string::size_type rightmostSlashIndex = #ifdef BSLS_PLATFORM_OS_WINDOWS filename.rfind('\\'); #else filename.rfind('/'); #endif if (bsl::string::npos == rightmostSlashIndex) { output += filename; } else { output += filename.substr(rightmostSlashIndex + 1); } } break; case 'l': { appendToString(&output, fixedFields.lineNumber()); } break; case 'c': { output += fixedFields.category(); } break; case 'm': { bslstl::StringRef message = fixedFields.messageRef(); output.append(message.data(), message.length()); } break; case 'x': { bsl::stringstream ss; int length = fixedFields.messageStreamBuf().length(); bdlb::Print::printString(ss, fixedFields.message(), length, false); output += ss.str(); } break; case 'X': { bsl::stringstream ss; int length = fixedFields.messageStreamBuf().length(); bdlb::Print::singleLineHexDump(ss, fixedFields.message(), length); output += ss.str(); } break; case 'u': { typedef ball::UserFields Values; const Values& userFields = record.userFields(); const int numUserFields = userFields.length(); if (numUserFields > 0) { bsl::stringstream ss; Values::ConstIterator it = userFields.begin(); ss << *it; ++it; for (; it != userFields.end(); ++it) { ss << " " << *it; } output += ss.str(); } } break; default: { // Undefined: we just output the verbatim characters. output += '%'; output += *iter; } } ++iter; } break; case '\\': { if (++iter == end) { break; } switch (*iter) { case 'n': { output += '\n'; } break; case 't': { output += '\t'; } break; case '\\': { output += '\\'; } break; default: { // Undefined: we just output the verbatim characters. output += '\\'; output += *iter; } } ++iter; } break; default: { output += *iter; ++iter; } } } #if defined(BSLS_PLATFORM_CMP_MSVC) #undef snprintf #endif stream.write(output.c_str(), output.size()); stream.flush(); }
// ACCESSORS void RecordStringFormatter::operator()(bsl::ostream& stream, const Record& record) const { const RecordAttributes& fixedFields = record.fixedFields(); bdlt::DatetimeInterval offset; if (k_ENABLE_PUBLISH_IN_LOCALTIME == d_timestampOffset.totalMilliseconds()) { bsls::Types::Int64 localTimeOffsetInSeconds = bdlt::LocalTimeOffset::localTimeOffset( fixedFields.timestamp()).totalSeconds(); offset.setTotalSeconds(localTimeOffsetInSeconds); } else if(k_DISABLE_PUBLISH_IN_LOCALTIME == d_timestampOffset.totalMilliseconds()) { // Do not adjust 'offset'. } else { offset = d_timestampOffset; } bdlt::DatetimeTz timestamp(fixedFields.timestamp() + offset, static_cast<int>(offset.totalMinutes())); // Step through the format string, outputting the required elements. const char* iter = d_formatSpec.data(); const char* end = iter + d_formatSpec.length(); // Create a buffer on the stack for formatting the record. Note that the // size of the buffer should be slightly larger than the amount we reserve // in order to ensure only a single allocation occurs. const int BUFFER_SIZE = 512; const int STRING_RESERVATION = BUFFER_SIZE - bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT; char fixedBuffer[BUFFER_SIZE]; bdlma::BufferedSequentialAllocator stringAllocator(fixedBuffer, BUFFER_SIZE); bsl::string output(&stringAllocator); output.reserve(STRING_RESERVATION); #if defined(BSLS_PLATFORM_CMP_MSVC) #define snprintf _snprintf #endif while (iter != end) { switch (*iter) { case '%': { if (++iter == end) { break; } switch (*iter) { case '%': { output += '%'; } break; case 'd': // fall through intentionally case 'D': { const int fractionalSecondPrecision = 'd' == *iter ? 3 : 6; char buffer[32]; timestamp.localDatetime().printToBuffer( buffer, sizeof buffer, fractionalSecondPrecision); output += buffer; } break; case 'I': // FALL THROUGH case 'O': // FALL THROUGH case 'i': { // Use ISO8601 "extended" format. const int fractionalSecondPrecision = 'O' == *iter ? 6 : 3; bdlt::Iso8601UtilConfiguration config; config.setFractionalSecondPrecision(fractionalSecondPrecision); config.setUseZAbbreviationForUtc(true); char buffer[bdlt::Iso8601Util::k_DATETIMETZ_STRLEN + 1]; int outputLength = bdlt::Iso8601Util::generateRaw(buffer, timestamp, config); if ('i' == *iter) { // Remove milliseconds part. enum { k_DECIMAL_SIGN_OFFSET = 19, k_TZINFO_OFFSET = k_DECIMAL_SIGN_OFFSET + 4 }; bslstl::StringRef head(buffer, k_DECIMAL_SIGN_OFFSET); bslstl::StringRef tail(buffer + k_TZINFO_OFFSET, outputLength - k_TZINFO_OFFSET); output += head + tail; } else { output.append(buffer, outputLength); } } break; case 'p': { appendToString(&output, fixedFields.processID()); } break; case 't': { appendToString(&output, fixedFields.threadID()); } break; case 's': { output += Severity::toAscii( (Severity::Level)fixedFields.severity()); } break; case 'f': { output += fixedFields.fileName(); } break; case 'F': { const bsl::string& filename = fixedFields.fileName(); bsl::string::size_type rightmostSlashIndex = #ifdef BSLS_PLATFORM_OS_WINDOWS filename.rfind('\\'); #else filename.rfind('/'); #endif if (bsl::string::npos == rightmostSlashIndex) { output += filename; } else { output += filename.substr(rightmostSlashIndex + 1); } } break; case 'l': { appendToString(&output, fixedFields.lineNumber()); } break; case 'c': { output += fixedFields.category(); } break; case 'm': { bslstl::StringRef message = fixedFields.messageRef(); output.append(message.data(), message.length()); } break; case 'x': { bsl::stringstream ss; int length = static_cast<int>( fixedFields.messageStreamBuf().length()); bdlb::Print::printString(ss, fixedFields.message(), length, false); output += ss.str(); } break; case 'X': { bsl::stringstream ss; int length = static_cast<int>( fixedFields.messageStreamBuf().length()); bdlb::Print::singleLineHexDump(ss, fixedFields.message(), length); output += ss.str(); } break; case 'u': { typedef ball::UserFields Values; const Values& customFields = record.customFields(); const int numCustomFields = customFields.length(); if (numCustomFields > 0) { bsl::stringstream ss; Values::ConstIterator it = customFields.begin(); ss << *it; ++it; for (; it != customFields.end(); ++it) { ss << " " << *it; } output += ss.str(); } } break; default: { // Undefined: we just output the verbatim characters. output += '%'; output += *iter; } } ++iter; } break; case '\\': { if (++iter == end) { break; } switch (*iter) { case 'n': { output += '\n'; } break; case 't': { output += '\t'; } break; case '\\': { output += '\\'; } break; default: { // Undefined: we just output the verbatim characters. output += '\\'; output += *iter; } } ++iter; } break; default: { output += *iter; ++iter; } } } #if defined(BSLS_PLATFORM_CMP_MSVC) #undef snprintf #endif stream.write(output.c_str(), output.size()); stream.flush(); }