Improve log print

PiperOrigin-RevId: 561734464
diff --git a/sim/BUILD b/sim/BUILD
index bbc4d99..dc21c6e 100644
--- a/sim/BUILD
+++ b/sim/BUILD
@@ -20,6 +20,7 @@
         "@com_google_absl//absl/functional:any_invocable",
         "@com_google_absl//absl/log:check",
         "@com_google_absl//absl/strings",
+        "@com_google_absl//absl/strings:str_format",
         "@com_google_mpact-riscv//riscv:riscv_state",
     ],
 )
diff --git a/sim/kelvin_state.cc b/sim/kelvin_state.cc
index 7e800cc..06b823b 100644
--- a/sim/kelvin_state.cc
+++ b/sim/kelvin_state.cc
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "absl/log/check.h"
+#include "absl/strings/str_format.h"
 #include "absl/strings/string_view.h"
 
 namespace kelvin::sim {
@@ -47,6 +48,7 @@
 // Print the logging message based on log_args_.
 void KelvinState::PrintLog(absl::string_view format_string) {
   char *print_ptr = const_cast<char *>(format_string.data());
+  std::string log_string = "";
   while (*print_ptr) {
     if (*print_ptr == '%') {
       CHECK_GT(log_args_.size(), 0)
@@ -54,15 +56,17 @@
       if (log_args_[0].type() == typeid(uint32_t)) {
         switch (print_ptr[1]) {
           case 'u':
-            std::cout << std::dec << std::any_cast<uint32_t>(log_args_[0]);
+            log_string +=
+                absl::StrFormat("%u", std::any_cast<uint32_t>(log_args_[0]));
             break;
           case 'd':
-            std::cout << std::dec
-                      << static_cast<int32_t>(
-                             std::any_cast<uint32_t>(log_args_[0]));
+            log_string += absl::StrFormat(
+                "%d",
+                static_cast<int32_t>(std::any_cast<uint32_t>(log_args_[0])));
             break;
           case 'x':
-            std::cout << std::hex << std::any_cast<uint32_t>(log_args_[0]);
+            log_string +=
+                absl::StrFormat("%x", std::any_cast<uint32_t>(log_args_[0]));
             break;
           default:
             std::cerr << "incorrect format" << std::endl;
@@ -71,17 +75,18 @@
       }
       if (log_args_[0].type() == typeid(std::string)) {
         if (print_ptr[1] == 's') {
-          std::cout << std::any_cast<std::string>(log_args_[0]);
+          log_string += std::any_cast<std::string>(log_args_[0]);
         } else {
           std::cerr << "incorrect format" << std::endl;
         }
       }
       log_args_.erase(log_args_.begin());
       print_ptr += 2;  // skip the format specifier too.
-    } else {
-      std::cout << *print_ptr++;
+    } else {  // Default. Just append the character from the format string.
+      log_string += *print_ptr++;
     }
   }
+  std::cout << log_string;
   // Flush log_args_
   log_args_.clear();
 }
diff --git a/sim/test/kelvin_log_instructions_test.cc b/sim/test/kelvin_log_instructions_test.cc
index e868a62..e86fa35 100644
--- a/sim/test/kelvin_log_instructions_test.cc
+++ b/sim/test/kelvin_log_instructions_test.cc
@@ -160,9 +160,9 @@
 }
 
 TEST_F(KelvinLogInstructionsTest, PrintTwoArguments) {
-  constexpr char kFormatString[] = "%s World %d\n";
+  constexpr char kFormatString[] = "%s World %x\n";
   constexpr uint32_t kCharStream = 0x00006948;  // "Hi"
-  constexpr uint32_t kPrintNum = 1337;
+  constexpr uint32_t kPrintNum = 0xbaddecaf;
 
   // Initialize memory.
   auto *db = state_->db_factory()->Allocate<char>(sizeof(kFormatString));
@@ -207,7 +207,7 @@
     instructions[i]->Execute(nullptr);
   }
   const std::string stdout_str = testing::internal::GetCapturedStdout();
-  EXPECT_EQ("Hi World 1337\n", stdout_str);
+  EXPECT_EQ("Hi World baddecaf\n", stdout_str);
 }
 
 }  // namespace