Skip to content

Commit

Permalink
Adding tracing (#121)
Browse files Browse the repository at this point in the history
The change aims to add detailed tracing to the extension's code.
Currently, we use logging to the VSs output window, but this has
limitations and should be used for conveying basic information.
Additionally, the output window is visible to users of the extension, so
it should not contain too many entries and details. The place where
details should be logged is tracing.

- Capability for dynamically enabling and disabling tracing
- When tracing is disabled, it does not impact performance
- Ability to filter entries additionally
- File logging (possibility to easy add custom targets where entries are
logged)
- Ability to view state of the extension in real time using external
tools

![Zrzut ekranu 2024-10-22
142258](https://github.com/user-attachments/assets/404b3efe-f496-42bc-8fcf-0c24309170e0)

![Zrzut ekranu 2024-10-22
142329](https://github.com/user-attachments/assets/6689bc55-4487-4b2c-8564-0c14e7eebb70)

---------

Co-authored-by: Tomasz Gołębiowski <tgolebiowski@virtuslab.com>
  • Loading branch information
tomaszgolebiowski and Tomasz Gołębiowski authored Oct 24, 2024
1 parent 6e5a6a4 commit 860b7f4
Show file tree
Hide file tree
Showing 10 changed files with 382 additions and 7 deletions.
6 changes: 6 additions & 0 deletions src/Cody.Core/Cody.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@
<Compile Include="Infrastructure\ISecretStorageService.cs" />
<Compile Include="Infrastructure\IProgressService.cs" />
<Compile Include="Logging\ITestLogger.cs" />
<Compile Include="Trace\FileTraceListener.cs" />
<Compile Include="Trace\LogioTraceListener.cs" />
<Compile Include="Trace\TraceEvent.cs" />
<Compile Include="Trace\TraceListener.cs" />
<Compile Include="Trace\TraceLogger.cs" />
<Compile Include="Trace\TraceManager.cs" />
<Compile Include="Workspace\IFileService.cs" />
<Compile Include="Ide\IVsVersionService.cs" />
<Compile Include="Infrastructure\WebViewsManager.cs" />
Expand Down
14 changes: 8 additions & 6 deletions src/Cody.Core/DocumentSync/DocumentSyncCallback.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Cody.Core.Agent;
using Cody.Core.Agent.Protocol;
using Cody.Core.Logging;
using Cody.Core.Trace;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -10,6 +11,8 @@ namespace Cody.Core.DocumentSync
{
public class DocumentSyncCallback : IDocumentSyncActions
{
private static readonly TraceLogger trace = new TraceLogger(nameof(DocumentSyncCallback));

private ILog logger;
private IAgentService agentService;

Expand All @@ -27,7 +30,7 @@ private string ToUri(string path)

public void OnChanged(string fullPath, DocumentRange visibleRange, DocumentRange selection, IEnumerable<DocumentChange> changes)
{
logger.Debug($"Sending didChange() for '{fullPath}', s:{selection}, v:{visibleRange}, c:{string.Join("", changes)}");
trace.TraceEvent("DidChange", "ch: '{0}', sel:{1}, vr:{2}, path:{3}", string.Join("", changes), selection, visibleRange, fullPath);

Range vRange = null;
if (visibleRange != null)
Expand Down Expand Up @@ -88,7 +91,7 @@ public void OnChanged(string fullPath, DocumentRange visibleRange, DocumentRange

public void OnClosed(string fullPath)
{
logger.Debug($"Sending DidClose() for '{fullPath}'");
trace.TraceEvent("DidClose", "{0}", fullPath);

var docState = new ProtocolTextDocument
{
Expand All @@ -101,14 +104,14 @@ public void OnClosed(string fullPath)

public void OnFocus(string fullPath)
{
logger.Debug($"Sending DidFocus() for '{fullPath}'");
trace.TraceEvent("DidFocus", "{0}", fullPath);
agentService.DidFocus(new CodyFilePath { Uri = ToUri(fullPath) });

}

public void OnOpened(string fullPath, string content, DocumentRange visibleRange, DocumentRange selection)
{
logger.Debug($"Sending DidOpen() for '{fullPath}', s:{selection}, v:{visibleRange}");
trace.TraceEvent("DidOpen", "sel:{0}, vr:{1}, path:{2}", selection, visibleRange, fullPath);

Range vRange = null;
if (visibleRange != null)
Expand Down Expand Up @@ -153,8 +156,7 @@ public void OnOpened(string fullPath, string content, DocumentRange visibleRange

public void OnSaved(string fullPath)
{
logger.Debug($"Sending DidSave() for '{fullPath}'");

trace.TraceEvent("DidSave", "{0}", fullPath);
agentService.DidSave(new CodyFilePath { Uri = ToUri(fullPath) });
}
}
Expand Down
60 changes: 60 additions & 0 deletions src/Cody.Core/Trace/FileTraceListener.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cody.Core.Trace
{
public class FileTraceListener : TraceListener
{
private StreamWriter writer;

public FileTraceListener(string fileName)
{
FileName = fileName;
}

public string FileName { get; }

protected override void Initialize()
{
var stream = File.Open(FileName, FileMode.Append, FileAccess.Write, FileShare.Read);
writer = new StreamWriter(stream);
writer.AutoFlush = true;
}

protected string FormatTraceEvent(TraceEvent traceEvent)
{
var sb = new StringBuilder();
var eventName = string.IsNullOrEmpty(traceEvent.EventName) ? "<none>" : traceEvent.EventName;
sb.AppendFormat("{0:yyyy-MM-dd HH:mm:ss.fff} [{1,2}] {2}.{3}: ", traceEvent.Timestamp, traceEvent.ThreadId, traceEvent.LoggerName, eventName);

if (!string.IsNullOrEmpty(traceEvent.Message))
{
sb.AppendFormat(traceEvent.Message, traceEvent.MessageArgs);
}

if (traceEvent.Data != null)
{
var output = JsonConvert.SerializeObject(traceEvent.Data);
sb.Append(output);
}

if (traceEvent.Exception != null)
{
sb.Append(traceEvent.Exception);
}

return sb.ToString();
}

protected override void Write(TraceEvent traceEvent)
{
var formatedTraceEvent = FormatTraceEvent(traceEvent);
writer.WriteLine(formatedTraceEvent);
}
}
}
74 changes: 74 additions & 0 deletions src/Cody.Core/Trace/LogioTraceListener.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Cody.Core.Trace
{
public class LogioTraceListener : TraceListener
{
private TcpClient client;
private NetworkStream stream;
private HashSet<string> inputs = new HashSet<string>();

public LogioTraceListener(string hostname, int port)
{
Hostname = hostname;
Port = port;
}

public string Hostname { get; }
public int Port { get; }

protected override void Initialize()
{
client = new TcpClient();
client.Connect(Hostname, Port);
stream = client.GetStream();
}

protected override void Write(TraceEvent traceEvent)
{
var eventName = string.IsNullOrEmpty(traceEvent.EventName) ? "<none>" : traceEvent.EventName;
var input = $"{traceEvent.LoggerName}|{eventName}";
if (!inputs.Contains(input))
{
var newInputMsg = $"+input|{input}\0";
var newInputBytes = Encoding.UTF8.GetBytes(newInputMsg);

stream.Write(newInputBytes, 0, newInputBytes.Length);

inputs.Add(input);
}

var sb = new StringBuilder();
sb.AppendFormat("[{1}]", traceEvent.ThreadId);
if (!string.IsNullOrEmpty(traceEvent.Message))
{
sb.Append(" ");
sb.AppendFormat(traceEvent.Message, traceEvent.MessageArgs);
}

if (traceEvent.Data != null)
{
var output = JsonConvert.SerializeObject(traceEvent.Data);
sb.Append(" ");
sb.Append(output);
}

if (traceEvent.Exception != null)
{
sb.Append(" ");
sb.Append(traceEvent.Exception);
}

var msg = $"+msg|{input}|{sb}\0";
var msgBytes = Encoding.UTF8.GetBytes(msg);

stream.Write(msgBytes, 0, msgBytes.Length);
}
}
}
34 changes: 34 additions & 0 deletions src/Cody.Core/Trace/TraceEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cody.Core.Trace
{
public class TraceEvent
{
public TraceEvent(string loggerName)
{
Timestamp = DateTime.Now;
ThreadId = Environment.CurrentManagedThreadId;
LoggerName = loggerName;
}

public string LoggerName { get; }

public DateTime Timestamp { get; }

public int ThreadId { get; }

public string EventName { get; set; }

public string Message { get; set; }

public object[] MessageArgs { get; set; }

public object Data { get; set; }

public Exception Exception { get; set; }
}
}
54 changes: 54 additions & 0 deletions src/Cody.Core/Trace/TraceListener.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cody.Core.Trace
{
public abstract class TraceListener
{
public bool Enabled { get; set; } = true;

public Func<TraceEvent, bool> Filter { get; set; }

private bool? successfullyInitialized;

protected abstract void Initialize();

public void WriteTraceEvent(TraceEvent traceEvent)
{
if (Enabled && traceEvent != null)
{
if (Filter != null && !Filter(traceEvent)) return;

if (successfullyInitialized == true)
{
try
{
Write(traceEvent);
return;
}
catch { }
}

if (successfullyInitialized == null)
{
try
{
Initialize();
successfullyInitialized = true;
Write(traceEvent);
}
catch
{
successfullyInitialized = false;
}
}

}
}

protected abstract void Write(TraceEvent traceEvent);
}
}
Loading

0 comments on commit 860b7f4

Please sign in to comment.