// Copyright Epic Games, Inc. All Rights Reserved. using System.Globalization; using System.Text; using Grpc.Core; namespace HordeServer.Utilities { /// /// Exception class designed to allow logging structured log messages /// public class StructuredRpcException : RpcException { /// /// The format string with named parameters /// public string Format { get; } /// /// The argument list /// public object[] Args { get; } /// /// Constructor /// /// Status code to return /// The format string /// Arguments for the format string public StructuredRpcException(StatusCode statusCode, string format, params object[] args) : base(new Status(statusCode, FormatMessage(format, args))) { Format = format; Args = args; } /// /// Replace named arguments in the format message with their values /// /// /// /// static string FormatMessage(string format, params object[] args) { string newFormat = ConvertToFormatString(format); return String.Format(CultureInfo.CurrentCulture, newFormat, args); } /// /// Converts a named parameter format string to a String.Format style string /// /// /// static string ConvertToFormatString(string format) { int argIdx = 0; StringBuilder newFormat = new StringBuilder(); for (int idx = 0; idx < format.Length; idx++) { char character = format[idx]; newFormat.Append(character); if (character == '{' && idx + 1 < format.Length) { char nextCharacter = format[idx + 1]; if ((nextCharacter >= 'a' && nextCharacter <= 'z') || (nextCharacter >= 'A' && nextCharacter <= 'Z') || nextCharacter == '_') { for (int endIdx = idx + 2; endIdx < format.Length; endIdx++) { if (format[endIdx] == ':' || format[endIdx] == '}') { newFormat.Append(argIdx++); idx = endIdx - 1; break; } } } } } return newFormat.ToString(); } } }