@@ -29,6 +29,53 @@ namespace AppInstaller::Logging
2929 return std::move (strstr).str ();
3030 }
3131
32+ // Formats a log line in CMTrace format.
33+ // CMTrace log format: <![LOG[message]LOG]!><time="HH:mm:ss.fff+###" date="MM-dd-YYYY" component="channel" context="" type="N" thread="TID" file="">
34+ std::string ToCMTraceLogLine (Channel channel, Level level, std::string_view message)
35+ {
36+ auto now = std::chrono::system_clock::now ();
37+ auto tt = std::chrono::system_clock::to_time_t (now);
38+ tm localTime{};
39+ _localtime64_s (&localTime, &tt);
40+
41+ auto sinceEpoch = now.time_since_epoch ();
42+ auto leftoverMillis = std::chrono::duration_cast<std::chrono::milliseconds>(sinceEpoch) - std::chrono::duration_cast<std::chrono::seconds>(sinceEpoch);
43+
44+ // Get UTC bias in minutes (positive means west of UTC, CMTrace uses positive for west)
45+ long timezoneBiasSeconds = 0 ;
46+ _get_timezone (&timezoneBiasSeconds);
47+ long biasMins = timezoneBiasSeconds / 60 ;
48+
49+ // CMTrace type: 1=Info/Verbose, 2=Warning, 3=Error/Critical
50+ int type;
51+ switch (level)
52+ {
53+ case Level::Warning: type = 2 ; break ;
54+ case Level::Error:
55+ case Level::Crit: type = 3 ; break ;
56+ default : type = 1 ; break ;
57+ }
58+
59+ std::stringstream strstr;
60+ strstr << " <![LOG[" << message << " ]LOG]!>"
61+ << " <time=\" "
62+ << std::setw (2 ) << std::setfill (' 0' ) << localTime.tm_hour << " :"
63+ << std::setw (2 ) << std::setfill (' 0' ) << localTime.tm_min << " :"
64+ << std::setw (2 ) << std::setfill (' 0' ) << localTime.tm_sec << " ."
65+ << std::setw (3 ) << std::setfill (' 0' ) << leftoverMillis.count ()
66+ << " +" << biasMins << " \" "
67+ << " date=\" "
68+ << std::setw (2 ) << std::setfill (' 0' ) << (1 + localTime.tm_mon ) << " -"
69+ << std::setw (2 ) << std::setfill (' 0' ) << localTime.tm_mday << " -"
70+ << (1900 + localTime.tm_year ) << " \" "
71+ << " component=\" " << GetChannelName (channel) << " \" "
72+ << " context=\"\" "
73+ << " type=\" " << type << " \" "
74+ << " thread=\" " << GetCurrentThreadId () << " \" "
75+ << " file=\"\" >" ;
76+ return std::move (strstr).str ();
77+ }
78+
3279 // Determines the difference between the given position and the maximum as an offset.
3380 std::ofstream::off_type CalculateDiff (const std::ofstream::pos_type& position, std::ofstream::off_type maximum)
3481 {
@@ -94,7 +141,15 @@ namespace AppInstaller::Logging
94141
95142 void FileLogger::Write (Channel channel, Level level, std::string_view message) noexcept try
96143 {
97- std::string log = ToLogLine (channel, level, message);
144+ std::string log;
145+ if (Settings::User ().Get <Settings::Setting::LoggingUseCMTrace>())
146+ {
147+ log = ToCMTraceLogLine (channel, level, message);
148+ }
149+ else
150+ {
151+ log = ToLogLine (channel, level, message);
152+ }
98153 WriteDirect (channel, level, log);
99154 }
100155 catch (...) {}
0 commit comments