Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[.NET] Safe logging #18

Merged
merged 1 commit into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 19 additions & 14 deletions dotnet/WorkbenchConnector/AgentBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public virtual async Task<IAgentConfig> UpdateAgentConfigAsync(
IAgentConfig? config,
CancellationToken cancellationToken = default)
{
this.Log.LogDebug("Updating agent '{0}' config", this.Id);
this.Log.LogDebug("Updating agent '{0}' config", this.Id.HtmlEncode());

this.RawConfig ??= this.GetDefaultConfig();
config ??= this.GetDefaultConfig();
Expand Down Expand Up @@ -143,7 +143,8 @@ public virtual async Task CreateConversationAsync(
string conversationId,
CancellationToken cancellationToken = default)
{
this.Log.LogDebug("Creating conversation '{0}' on agent '{1}'", conversationId, this.Id);
this.Log.LogDebug("Creating conversation '{0}' on agent '{1}'",
conversationId.HtmlEncode(), this.Id.HtmlEncode());

Conversation conversation = await this.Storage.GetConversationAsync(conversationId, this.Id, cancellationToken).ConfigureAwait(false)
?? new Conversation(conversationId, this.Id);
Expand All @@ -164,7 +165,8 @@ public virtual Task DeleteConversationAsync(
string conversationId,
CancellationToken cancellationToken = default)
{
this.Log.LogDebug("Deleting conversation '{0}' on agent '{1}'", conversationId, this.Id);
this.Log.LogDebug("Deleting conversation '{0}' on agent '{1}'",
conversationId.HtmlEncode(), this.Id.HtmlEncode());
return this.Storage.DeleteConversationAsync(conversationId, this.Id, cancellationToken);
}

Expand All @@ -178,7 +180,8 @@ public virtual async Task<bool> ConversationExistsAsync(
string conversationId,
CancellationToken cancellationToken = default)
{
this.Log.LogDebug("Checking if conversation '{0}' on agent '{1}' exists", conversationId, this.Id);
this.Log.LogDebug("Checking if conversation '{0}' on agent '{1}' exists",
conversationId.HtmlEncode(), this.Id.HtmlEncode());
var conversation = await this.Storage.GetConversationAsync(conversationId, this.Id, cancellationToken).ConfigureAwait(false);
return conversation != null;
}
Expand All @@ -194,7 +197,8 @@ public virtual async Task AddParticipantAsync(
Participant participant,
CancellationToken cancellationToken = default)
{
this.Log.LogDebug("Adding participant to conversation '{0}' on agent '{1}'", conversationId, this.Id);
this.Log.LogDebug("Adding participant to conversation '{0}' on agent '{1}'",
conversationId.HtmlEncode(), this.Id.HtmlEncode());

Conversation conversation = await this.Storage.GetConversationAsync(conversationId, this.Id, cancellationToken).ConfigureAwait(false)
?? new Conversation(conversationId, this.Id);
Expand All @@ -214,7 +218,8 @@ public virtual async Task RemoveParticipantAsync(
Participant participantUpdatedEvent,
CancellationToken cancellationToken = default)
{
this.Log.LogDebug("Removing participant from conversation '{0}' on agent '{1}'", conversationId, this.Id);
this.Log.LogDebug("Removing participant from conversation '{0}' on agent '{1}'",
conversationId.HtmlEncode(), this.Id.HtmlEncode());

Conversation? conversation = await this.Storage.GetConversationAsync(conversationId, this.Id, cancellationToken).ConfigureAwait(false);
if (conversation == null) { return; }
Expand All @@ -235,7 +240,7 @@ public virtual Task ReceiveMessageAsync(
CancellationToken cancellationToken = default)
{
this.Log.LogDebug("Received {0} chat message in conversation '{1}' with agent '{2}' from '{3}' '{4}'",
message.ContentType, conversationId, this.Id, message.Sender.Role, message.Sender.Id);
message.ContentType.HtmlEncode(), conversationId.HtmlEncode(), this.Id.HtmlEncode(), message.Sender.Role.HtmlEncode(), message.Sender.Id.HtmlEncode());

// Update the chat history to include the message received
return this.AddMessageToHistoryAsync(conversationId, message, cancellationToken);
Expand All @@ -255,7 +260,7 @@ public virtual Task ReceiveNoticeAsync(
CancellationToken cancellationToken = default)
{
this.Log.LogDebug("Received {0} notice in conversation '{1}' with agent '{2}' from '{3}' '{4}': {5}",
message.ContentType, conversationId, this.Id, message.Sender.Role, message.Sender.Id, message.Content);
message.ContentType.HtmlEncode(), conversationId.HtmlEncode(), this.Id.HtmlEncode(), message.Sender.Role.HtmlEncode(), message.Sender.Id.HtmlEncode(), message.Content.HtmlEncode());

return Task.CompletedTask;
}
Expand All @@ -273,7 +278,7 @@ public virtual Task ReceiveNoteAsync(
CancellationToken cancellationToken = default)
{
this.Log.LogDebug("Received {0} note in conversation '{1}' with agent '{2}' from '{3}' '{4}': {5}",
message.ContentType, conversationId, this.Id, message.Sender.Role, message.Sender.Id, message.Content);
message.ContentType.HtmlEncode(), conversationId.HtmlEncode(), this.Id.HtmlEncode(), message.Sender.Role.HtmlEncode(), message.Sender.Id.HtmlEncode(), message.Content.HtmlEncode());

return Task.CompletedTask;
}
Expand All @@ -290,7 +295,7 @@ public virtual Task ReceiveCommandAsync(
CancellationToken cancellationToken = default)
{
this.Log.LogDebug("Received '{0}' command in conversation '{1}' with agent '{2}' from '{3}' '{4}': {5}",
command.CommandName, conversationId, this.Id, command.Sender.Role, command.Sender.Id, command.Content);
command.CommandName.HtmlEncode(), conversationId.HtmlEncode(), this.Id.HtmlEncode(), command.Sender.Role.HtmlEncode(), command.Sender.Id.HtmlEncode(), command.Content.HtmlEncode());

return Task.CompletedTask;
}
Expand All @@ -307,7 +312,7 @@ public virtual Task ReceiveCommandResponseAsync(
CancellationToken cancellationToken = default)
{
this.Log.LogDebug("Received {0} command response in conversation '{1}' with agent '{2}' from '{3}' '{4}': {5}",
message.ContentType, conversationId, this.Id, message.Sender.Role, message.Sender.Id, message.Content);
message.ContentType.HtmlEncode(), conversationId.HtmlEncode(), this.Id.HtmlEncode(), message.Sender.Role.HtmlEncode(), message.Sender.Id.HtmlEncode(), message.Content.HtmlEncode());

return Task.CompletedTask;
}
Expand All @@ -324,7 +329,7 @@ public virtual async Task DeleteMessageAsync(
CancellationToken cancellationToken = default)
{
this.Log.LogDebug("Deleting message in conversation '{0}' with agent '{1}', message from '{2}' '{3}'",
conversationId, this.Id, message.Sender.Role, message.Sender.Id);
conversationId.HtmlEncode(), this.Id.HtmlEncode(), message.Sender.Role.HtmlEncode(), message.Sender.Id.HtmlEncode());

// return this.DeleteMessageFromHistoryAsync(conversationId, message, cancellationToken);
Conversation? conversation = await this.Storage.GetConversationAsync(conversationId, this.Id, cancellationToken).ConfigureAwait(false);
Expand Down Expand Up @@ -379,7 +384,7 @@ protected virtual Task SetAgentStatusAsync(
string content,
CancellationToken cancellationToken = default)
{
this.Log.LogWarning("Change agent '{0}' status in conversation '{1}'", this.Id, conversationId);
this.Log.LogWarning("Change agent '{0}' status in conversation '{1}'", this.Id.HtmlEncode(), conversationId.HtmlEncode());
return this.WorkbenchConnector.SetAgentStatusAsync(this.Id, conversationId, content, cancellationToken);
}

Expand All @@ -392,7 +397,7 @@ protected virtual Task ResetAgentStatusAsync(
string conversationId,
CancellationToken cancellationToken = default)
{
this.Log.LogWarning("Reset agent '{0}' status in conversation '{1}'", this.Id, conversationId);
this.Log.LogWarning("Reset agent '{0}' status in conversation '{1}'", this.Id.HtmlEncode(), conversationId.HtmlEncode());
return this.WorkbenchConnector.ResetAgentStatusAsync(this.Id, conversationId, cancellationToken);
}
}
4 changes: 3 additions & 1 deletion dotnet/WorkbenchConnector/Storage/AgentServiceStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ public Task DeleteInsightAsync(string agentId, string conversationId, string ins

private async Task<List<T>> GetAllAsync<T>(string prefix, string suffix, CancellationToken cancellationToken = default)
{
this._log.LogTrace("Searching all files with prefix '{0}' and suffix '{1}'", prefix, suffix);
this._log.LogTrace("Searching all files with prefix '{0}' and suffix '{1}'",
prefix.HtmlEncode(), suffix.HtmlEncode());

var result = new List<T>();
string[] fileEntries = Directory.GetFiles(this._path);
foreach (string filePath in fileEntries)
Expand Down
39 changes: 39 additions & 0 deletions dotnet/WorkbenchConnector/StringLoggingExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Text;
using System.Web;
using Microsoft.AspNetCore.Http;

namespace Microsoft.SemanticWorkbench.Connector;

public static class StringLoggingExtensions
{
public static string HtmlEncode(this string? value)
{
return string.IsNullOrWhiteSpace(value)
? $"{value}"
: HttpUtility.HtmlEncode(value);
}

public static string HtmlEncode(this PathString value)
{
return string.IsNullOrWhiteSpace(value)
? $"{value}"
: HttpUtility.HtmlEncode(value);
}

public static string HtmlEncode(this StringBuilder value)
{
var s = value.ToString();
return string.IsNullOrWhiteSpace(s)
? $"{s}"
: HttpUtility.HtmlEncode(s);
}

public static string HtmlEncode(this object? value)
{
return value == null
? string.Empty
: HttpUtility.HtmlEncode(value.ToString() ?? string.Empty);
}
}
50 changes: 31 additions & 19 deletions dotnet/WorkbenchConnector/Webservice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ public static IEndpointRouteBuilder UseCreateAgentEndpoint(
string? name = agentId;
Dictionary<string, string>? settings = JsonSerializer.Deserialize<Dictionary<string, string>>(data);
settings?.TryGetValue("assistant_name", out name);
log.LogDebug("Received request to create/update agent instance '{0}', name '{1}'", agentId, name);

log.LogDebug("Received request to create/update agent instance '{0}', name '{1}'",
agentId.HtmlEncode(), name.HtmlEncode());

var agent = workbenchConnector.GetAgent(agentId);
if (agent == null)
Expand All @@ -91,7 +93,7 @@ public static IEndpointRouteBuilder UseDeleteAgentEndpoint(
[FromServices] ILogger<SemanticWorkbenchWebservice> log,
CancellationToken cancellationToken) =>
{
log.LogDebug("Received request to deleting agent instance '{0}'", agentId);
log.LogDebug("Received request to deleting agent instance '{0}'", agentId.HtmlEncode());
await workbenchConnector.DeleteAgentAsync(agentId, cancellationToken).ConfigureAwait(false);
return Results.Ok();
});
Expand All @@ -109,7 +111,7 @@ public static IEndpointRouteBuilder UseFetchAgentConfigEndpoint(
[FromServices] WorkbenchConnector workbenchConnector,
[FromServices] ILogger<SemanticWorkbenchWebservice> log) =>
{
log.LogDebug("Received request to fetch agent '{0}' configuration", agentId);
log.LogDebug("Received request to fetch agent '{0}' configuration", agentId.HtmlEncode());

var agent = workbenchConnector.GetAgent(agentId);
if (agent == null)
Expand All @@ -135,13 +137,14 @@ public static IEndpointRouteBuilder UseSaveAgentConfigEndpoint(
[FromServices] ILogger<SemanticWorkbenchWebservice> log,
CancellationToken cancellationToken) =>
{
log.LogDebug("Received request to update agent '{0}' configuration", agentId);
log.LogDebug("Received request to update agent '{0}' configuration", agentId.HtmlEncode());

var agent = workbenchConnector.GetAgent(agentId);
if (agent == null) { return Results.NotFound("Agent Not Found"); }

var config = agent.ParseConfig(data["config"]);
IAgentConfig newConfig = await agent.UpdateAgentConfigAsync(config, cancellationToken).ConfigureAwait(false);
IAgentConfig newConfig =
await agent.UpdateAgentConfigAsync(config, cancellationToken).ConfigureAwait(false);

var tmp = workbenchConnector.GetAgent(agentId);

Expand All @@ -165,7 +168,8 @@ private static IEndpointRouteBuilder UseCreateConversationEndpoint(
[FromServices] ILogger<SemanticWorkbenchWebservice> log,
CancellationToken cancellationToken) =>
{
log.LogDebug("Received request to create conversation '{0}' on agent '{1}'", conversationId, agentId);
log.LogDebug("Received request to create conversation '{0}' on agent '{1}'",
conversationId.HtmlEncode(), agentId.HtmlEncode());

var agent = workbenchConnector.GetAgent(agentId);
if (agent == null) { return Results.NotFound("Agent Not Found"); }
Expand All @@ -190,7 +194,8 @@ public static IEndpointRouteBuilder UseFetchConversationStatesEndpoint(
[FromServices] ILogger<SemanticWorkbenchWebservice> log,
CancellationToken cancellationToken) =>
{
log.LogDebug("Received request to fetch agent '{0}' conversation '{1}' states", agentId, conversationId);
log.LogDebug("Received request to fetch agent '{0}' conversation '{1}' states",
agentId.HtmlEncode(), conversationId.HtmlEncode());

var agent = workbenchConnector.GetAgent(agentId);
if (agent == null) { return Results.NotFound("Conversation Not Found"); }
Expand Down Expand Up @@ -260,7 +265,8 @@ public static IEndpointRouteBuilder UseFetchConversationInsightEndpoint(
[FromServices] ILogger<SemanticWorkbenchWebservice> log,
CancellationToken cancellationToken) =>
{
log.LogDebug("Received request to fetch agent '{0}' conversation '{1}' insight '{2}'", agentId, conversationId, insightId);
log.LogDebug("Received request to fetch agent '{0}' conversation '{1}' insight '{2}'",
agentId.HtmlEncode(), conversationId.HtmlEncode(), insightId.HtmlEncode());

var agent = workbenchConnector.GetAgent(agentId);
if (agent == null) { return Results.NotFound("Agent Not Found"); }
Expand Down Expand Up @@ -323,7 +329,8 @@ private static IEndpointRouteBuilder UseCreateConversationEventEndpoint(
[FromServices] ILogger<SemanticWorkbenchWebservice> log,
CancellationToken cancellationToken) =>
{
log.LogDebug("Received request to process new event for agent '{0}' on conversation '{1}'", agentId, conversationId);
log.LogDebug("Received request to process new event for agent '{0}' on conversation '{1}'",
agentId.HtmlEncode(), conversationId.HtmlEncode());

if (data == null || !data.TryGetValue("event", out object? eventType))
{
Expand All @@ -340,7 +347,8 @@ private static IEndpointRouteBuilder UseCreateConversationEventEndpoint(
}

var json = JsonSerializer.Serialize(data);
log.LogDebug("Agent '{0}', conversation '{1}', Event '{2}'", agentId, conversationId, eventType);
log.LogDebug("Agent '{0}', conversation '{1}', Event '{2}'",
agentId.HtmlEncode(), conversationId.HtmlEncode(), eventType.HtmlEncode());
switch (eventType.ToString())
{
case "participant.created":
Expand Down Expand Up @@ -401,8 +409,11 @@ private static IEndpointRouteBuilder UseCreateConversationEventEndpoint(
break;

default:
log.LogInformation($"{message.MessageType}: {message.Content}");
log.LogWarning("Agent '{0}', conversation '{1}', Message type '{2}' ignored", agentId, conversationId, message.MessageType);
log.LogInformation("{0}: {1}", message.MessageType.HtmlEncode(),
message.Content.HtmlEncode());
log.LogWarning("Agent '{0}', conversation '{1}', Message type '{2}' ignored",
agentId.HtmlEncode(), conversationId.HtmlEncode(),
message.MessageType.HtmlEncode());
break;
}

Expand Down Expand Up @@ -483,8 +494,8 @@ private static IEndpointRouteBuilder UseCreateConversationEventEndpoint(
}
}
*/
log.LogWarning("Event type '{0}' not supported", eventType);
log.LogTrace(json);
log.LogWarning("Event type '{0}' not supported", eventType.HtmlEncode());
log.LogTrace(json.HtmlEncode());
break;
}

Expand All @@ -507,7 +518,8 @@ public static IEndpointRouteBuilder UseDeleteConversationEndpoint(
[FromServices] ILogger<SemanticWorkbenchWebservice> log,
CancellationToken cancellationToken) =>
{
log.LogDebug("Received request to delete conversation '{0}' on agent instance '{1}'", conversationId, agentId);
log.LogDebug("Received request to delete conversation '{0}' on agent instance '{1}'",
conversationId.HtmlEncode(), agentId.HtmlEncode());

var agent = workbenchConnector.GetAgent(agentId);
if (agent == null) { return Results.Ok(); }
Expand Down Expand Up @@ -542,13 +554,13 @@ private static IEndpointRouteBuilder UseCatchAllEndpoint(
string requestBody = await reader.ReadToEndAsync().ConfigureAwait(false);
context.Request.Body.Position = 0;

log.LogWarning("Unknown request: {0} Path: {1}", context.Request.Method, context.Request.Path);
log.LogWarning("Unknown request: {0} Path: {1}", context.Request.Method, context.Request.Path.HtmlEncode());

string? query = context.Request.QueryString.Value;
if (!string.IsNullOrEmpty(query)) { log.LogDebug("Query: {0}", context.Request.QueryString.Value); }
if (!string.IsNullOrEmpty(query)) { log.LogDebug("Query: {0}", context.Request.QueryString.Value.HtmlEncode()); }

log.LogDebug("Headers: {0}", headersStringBuilder.ToString());
log.LogDebug("Body: {0}", requestBody);
log.LogDebug("Headers: {0}", headersStringBuilder.HtmlEncode());
log.LogDebug("Body: {0}", requestBody.HtmlEncode());

return Results.NotFound("Request not supported");
});
Expand Down
Loading