lg2: support exception conversion

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I4b3cb55c9d03ed04b1f072bf3f5ef98ccffb0eef
diff --git a/docs/structured-logging.md b/docs/structured-logging.md
index 74c3e41..6801279 100644
--- a/docs/structured-logging.md
+++ b/docs/structured-logging.md
@@ -108,7 +108,8 @@
 
 The APIs can handle (and format appropriately) any data of the following
 types: signed or unsigned integers, floating point numbers, booleans, strings
-(C-strings, std::strings, or std::string_views), sdbusplus enums, and pointers.
+(C-strings, std::strings, or std::string_views), sdbusplus enums, exceptions,
+and pointers.
 
 The APIs also perform compile-time analysis of the arguments to give descriptive
 error messages for incorrect parameters or format flags.  Some examples are:
diff --git a/lib/include/phosphor-logging/lg2/conversion.hpp b/lib/include/phosphor-logging/lg2/conversion.hpp
index 4c860d4..b8e0633 100644
--- a/lib/include/phosphor-logging/lg2/conversion.hpp
+++ b/lib/include/phosphor-logging/lg2/conversion.hpp
@@ -47,6 +47,9 @@
 template <typename T>
 concept sdbusplus_enum = sdbusplus::message::has_convert_from_string_v<T>;
 
+template <typename T>
+concept exception_type = std::derived_from<std::decay_t<T>, std::exception>;
+
 /** Concept listing all of the types we know how to convert into a format
  *  for logging.
  */
@@ -54,7 +57,7 @@
 concept unsupported_log_convert_types =
     !(unsigned_integral_except_bool<T> || std::signed_integral<T> ||
       std::same_as<bool, T> || std::floating_point<T> || string_like_type<T> ||
-      pointer_type<T> || sdbusplus_enum<T>);
+      pointer_type<T> || sdbusplus_enum<T> || exception_type<T>);
 
 /** Any type we do not know how to convert for logging gives a nicer
  *  static_assert message. */
@@ -215,6 +218,26 @@
                            reinterpret_cast<uint64_t>(v));
 }
 
+/* Logging conversion for exceptions. */
+template <log_flags... Fs, exception_type V>
+static auto log_convert(const char* h, log_flag<Fs...> f, V&& v)
+{
+    // Compile-time checks for valid formatting flags.
+    prohibit(f, bin);
+    prohibit(f, dec);
+    prohibit(f, field16);
+    prohibit(f, field32);
+    prohibit(f, field64);
+    prohibit(f, field8);
+    prohibit(f, floating);
+    prohibit(f, hex);
+    prohibit(f, signed_val);
+    prohibit(f, unsigned_val);
+
+    // Treat like a string, but get the 'what' from the exception.
+    return std::make_tuple(h, (f | str).value, v.what());
+}
+
 /** Class to facilitate walking through the arguments of the `lg2::log` function
  *  and ensuring correct parameter types and conversion operations.
  */