Skip to content

Commit 9bb9f8a

Browse files
authored
Add basic logging for error cases in the Azure agent (#250)
- Use `Serilog` as it supports file logging. I considered `Microsoft.Extension.Logging` which has built-in logging provider for Event Source, but decided to not use it because it's easier to share a file log for diagnosis purposes. - The logging is configured to be rolling over by day, and it uses async writing to the log file. - The logging enabled so far is error only, but we can add more information/debug loggings for better view of the code operation. - We will need to allow a user to disable logging in the agent's configuration file. **This is not done in this PR.**
1 parent f10b94c commit 9bb9f8a

File tree

5 files changed

+31
-7
lines changed

5 files changed

+31
-7
lines changed

shell/agents/Microsoft.Azure.Agent/AzureAgent.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System.Diagnostics;
22
using System.Text;
3+
34
using AIShell.Abstraction;
5+
using Serilog;
46

57
namespace Microsoft.Azure.Agent;
68

@@ -16,6 +18,7 @@ public sealed class AzureAgent : ILLMAgent
1618
internal ArgumentPlaceholder ArgPlaceholder { set; get; }
1719

1820
private const string SettingFileName = "az.agent.json";
21+
private const string LoggingFileName = "log..txt";
1922
private const string InstructionPrompt = """
2023
NOTE: follow the below instructions when generating responses that include Azure CLI commands with placeholders:
2124
1. User's OS is `{0}`. Make sure the generated commands are suitable for the specified OS.
@@ -33,6 +36,7 @@ 7. DO NOT include the placeholder summary when the commands contains no placehol
3336
""";
3437

3538
private int _turnsLeft;
39+
3640
private readonly string _instructions;
3741
private readonly StringBuilder _buffer;
3842
private readonly HttpClient _httpClient;
@@ -73,12 +77,23 @@ public void Dispose()
7377
ArgPlaceholder?.DataRetriever?.Dispose();
7478
_chatSession.Dispose();
7579
_httpClient.Dispose();
80+
81+
Log.CloseAndFlush();
7682
}
7783

7884
public void Initialize(AgentConfig config)
7985
{
8086
_turnsLeft = int.MaxValue;
8187
SettingFile = Path.Combine(config.ConfigurationRoot, SettingFileName);
88+
89+
string logFile = Path.Combine(config.ConfigurationRoot, LoggingFileName);
90+
Log.Logger = new LoggerConfiguration()
91+
.WriteTo.Async(a => a.File(
92+
path: logFile,
93+
outputTemplate: "{Timestamp:HH:mm:ss} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
94+
rollingInterval: RollingInterval.Day))
95+
.CreateLogger();
96+
Log.Information("Azure agent initialized.");
8297
}
8398

8499
public IEnumerable<CommandBase> GetCommands() => [new ReplaceCommand(this)];
@@ -129,12 +144,12 @@ public async Task<bool> ChatAsync(string input, IShell shell)
129144
data = ParseCLIHandlerResponse(copilotResponse, shell);
130145
}
131146

132-
string answer = data is null ? copilotResponse.Text : GenerateAnswer(data);
133147
if (data?.PlaceholderSet is not null)
134148
{
135149
ArgPlaceholder = new ArgumentPlaceholder(input, data, _httpClient);
136150
}
137151

152+
string answer = data is null ? copilotResponse.Text : GenerateAnswer(data);
138153
host.RenderFullResponse(answer);
139154
}
140155
else
@@ -293,6 +308,7 @@ private ResponseData ParseCLIHandlerResponse(CopilotResponse copilotResponse, IS
293308
{
294309
// The placeholder section is not in the format as we've instructed ...
295310
// TODO: send telemetry about this case.
311+
Log.Error("Placeholder section not in expected format:\n{0}", text);
296312
}
297313

298314
ReplaceKnownPlaceholders(data);

shell/agents/Microsoft.Azure.Agent/AzureCopilotReceiver.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using System.Runtime.ExceptionServices;
44
using System.Text.Json;
55

6+
using Serilog;
7+
68
namespace Microsoft.Azure.Agent;
79

810
internal class AzureCopilotReceiver : IDisposable
@@ -57,14 +59,14 @@ private async Task ProcessActivities()
5759
}
5860
catch (OperationCanceledException)
5961
{
60-
// TODO: log the cancellation of the message receiving thread.
6162
// Close the web socket before the thread is going away.
6263
closingMessage = "Client closing";
64+
Log.Error("[AzureCopilotReceiver] Receiver thread cancelled, which means the instance was disposed.");
6365
}
6466

6567
if (closingMessage is not null)
6668
{
67-
// TODO: log the closing request.
69+
Log.Error("[AzureCopilotReceiver] Sending web socket closing request, message: '{0}'", closingMessage);
6870
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, closingMessage, CancellationToken.None);
6971
_activityQueue.CompleteAdding();
7072
break;
@@ -100,7 +102,7 @@ private async Task ProcessActivities()
100102
}
101103
}
102104

103-
// TODO: log the current state of the web socket.
105+
Log.Error("[AzureCopilotReceiver] Web socket connection dropped. State: '{0}'", _webSocket.State);
104106
_activityQueue.Add(new CopilotActivity { Error = new ConnectionDroppedException($"The websocket got in '{_webSocket.State}' state. Connection dropped.") });
105107
_activityQueue.CompleteAdding();
106108
}

shell/agents/Microsoft.Azure.Agent/ChatSession.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Text;
44
using System.Text.Json;
55
using System.Text.Json.Nodes;
6+
67
using AIShell.Abstraction;
78

89
namespace Microsoft.Azure.Agent;
@@ -75,8 +76,7 @@ internal async Task RefreshAsync(IHost host, CancellationToken cancellationToken
7576
else
7677
{
7778
host.WriteErrorLine()
78-
.WriteErrorLine($"Failed to start a conversation due to the following error: {e.Message}")
79-
.WriteErrorLine(e.StackTrace)
79+
.WriteErrorLine($"Failed to start a conversation due to the following error: {e.Message}\n{e.StackTrace}")
8080
.WriteErrorLine()
8181
.WriteErrorLine("Please try '/refresh' to start a new conversation.")
8282
.WriteErrorLine();

shell/agents/Microsoft.Azure.Agent/DataRetriever.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
using System.Text;
55
using System.Text.Json;
66
using System.Text.RegularExpressions;
7+
78
using AIShell.Abstraction;
9+
using Serilog;
810

911
namespace Microsoft.Azure.Agent;
1012

@@ -573,11 +575,13 @@ private AzCLICommand QueryForMetadata(string azCommand)
573575
else
574576
{
575577
// TODO: telemetry.
578+
Log.Error("[QueryForMetadata] Received status code '{0}' for command '{1}'", response.StatusCode, azCommand);
576579
}
577580
}
578-
catch (Exception)
581+
catch (Exception e)
579582
{
580583
// TODO: telemetry.
584+
Log.Error(e, "[QueryForMetadata] Exception while processing command: {0}", azCommand);
581585
}
582586

583587
return command;

shell/agents/Microsoft.Azure.Agent/Microsoft.Azure.Agent.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
<ItemGroup>
1919
<PackageReference Include="Azure.Identity" Version="1.11.4" />
2020
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
21+
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
22+
<PackageReference Include="Serilog.Sinks.Async" Version="2.0.0" />
2123
</ItemGroup>
2224

2325
<ItemGroup>

0 commit comments

Comments
 (0)