diff --git a/src/LibChorus/LibChorus.csproj b/src/LibChorus/LibChorus.csproj
index 70f2c232..b93c90a4 100644
--- a/src/LibChorus/LibChorus.csproj
+++ b/src/LibChorus/LibChorus.csproj
@@ -6,6 +6,7 @@
SIL.Chorus.LibChorus
net462;netstandard2.0
https://github.com/sillsdev/chorus.git
+ default
@@ -21,6 +22,7 @@
+
diff --git a/src/LibChorus/LibChorusActivitySource.cs b/src/LibChorus/LibChorusActivitySource.cs
new file mode 100644
index 00000000..71295fba
--- /dev/null
+++ b/src/LibChorus/LibChorusActivitySource.cs
@@ -0,0 +1,26 @@
+// Copyright (c) 2025-2025 SIL International
+// This software is licensed under the MIT License (http://opensource.org/licenses/MIT)
+
+using System.Diagnostics;
+using Chorus.VcsDrivers.Mercurial;
+using JetBrains.Annotations;
+
+namespace Chorus
+{
+ public static class LibChorusActivitySource
+ {
+ public const string ActivitySourceName = "SIL.LibChorus";
+ internal static readonly ActivitySource Value = new ActivitySource(ActivitySourceName);
+
+ public static void TagResumableParameters(this Activity activity, string direction, HgResumeApiParameters request)
+ {
+ if (activity is null) return;
+ activity.SetTag($"app.chorus.resumable.{direction}.chunk-size", request.ChunkSize);
+ activity.SetTag($"app.chorus.resumable.{direction}.bundle-size", request.BundleSize);
+ activity.SetTag($"app.chorus.resumable.{direction}.start-of-window", request.StartOfWindow);
+ activity.SetTag($"app.chorus.resumable.{direction}.trans-id", request.TransId);
+ activity.SetTag($"app.chorus.resumable.{direction}.repo-id", request.RepoId);
+ activity.SetTag($"app.chorus.resumable.{direction}.quantity", request.Quantity);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LibChorus/VcsDrivers/Mercurial/HgResumeTransport.cs b/src/LibChorus/VcsDrivers/Mercurial/HgResumeTransport.cs
index b2e506c6..5672524f 100644
--- a/src/LibChorus/VcsDrivers/Mercurial/HgResumeTransport.cs
+++ b/src/LibChorus/VcsDrivers/Mercurial/HgResumeTransport.cs
@@ -505,6 +505,9 @@ private PushStatus FinishPush(string transactionId)
private PushResponse PushOneChunk(HgResumeApiParameters request, byte[] dataToPush)
{
+ using var activity = LibChorusActivitySource.Value.StartActivity();
+ activity?.TagResumableParameters("push", request);
+
var pushResponse = new PushResponse(PushStatus.Fail);
try
{
@@ -810,6 +813,9 @@ private PullStatus FinishPull(string transactionId)
private PullResponse PullOneChunk(HgResumeApiParameters request)
{
+ using var activity = LibChorusActivitySource.Value.StartActivity();
+ activity?.TagResumableParameters("pull", request);
+
var pullResponse = new PullResponse(PullStatus.Fail);
try
{
diff --git a/src/LibChorus/VcsDrivers/Mercurial/HgRunner.cs b/src/LibChorus/VcsDrivers/Mercurial/HgRunner.cs
index e7cbe8e6..78cd0c75 100644
--- a/src/LibChorus/VcsDrivers/Mercurial/HgRunner.cs
+++ b/src/LibChorus/VcsDrivers/Mercurial/HgRunner.cs
@@ -4,6 +4,7 @@
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
+using Chorus.Model;
using Chorus.Utilities;
using SIL.Progress;
using SIL.Reporting;
@@ -44,10 +45,14 @@ public static ExecutionResult Run(string commandLine, string fromDirectory)
public static ExecutionResult Run(string commandLine, string fromDirectory, int secondsBeforeTimeOut, IProgress progress)
{
+ using var activity = LibChorusActivitySource.Value.StartActivity();
+ activity?.SetTag("app.hg.cmd", ServerSettingsModel.RemovePasswordForLog(commandLine));
+ activity?.SetTag("app.hg.timeout-sec", secondsBeforeTimeOut);
ExecutionResult result = new ExecutionResult();
Process process = new Process();
if (String.IsNullOrEmpty(MercurialLocation.PathToMercurialFolder))
{
+ activity?.SetStatus(ActivityStatusCode.Error, "Mercurial location not configured");
throw new ApplicationException("Mercurial location has not been configured.");
}
process.StartInfo.EnvironmentVariables["PYTHONPATH"] = Path.Combine(MercurialLocation.PathToMercurialFolder, "library.zip");
@@ -60,6 +65,7 @@ public static ExecutionResult Run(string commandLine, string fromDirectory, int
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WorkingDirectory = fromDirectory;
process.StartInfo.FileName = MercurialLocation.PathToHgExecutable;
+ activity?.SetTag("app.hg.binary-path", MercurialLocation.PathToHgExecutable);
var debug = Environment.GetEnvironmentVariable(@"CHORUSDEBUGGING") == null ? String.Empty : @"--debug ";
process.StartInfo.Arguments = commandLine.Replace("hg ", debug); //we don't want the whole command line, just the args portion
@@ -69,6 +75,7 @@ public static ExecutionResult Run(string commandLine, string fromDirectory, int
process.StartInfo.StandardErrorEncoding = System.Text.Encoding.UTF8;
if(!String.IsNullOrEmpty(debug))
{
+ activity?.SetTag("app.hg.debug", true);
Logger.WriteEvent("Running hg command: hg --debug {0}", commandLine);
}
try
@@ -128,16 +135,19 @@ public static ExecutionResult Run(string commandLine, string fromDirectory, int
{
result.StandardError += Environment.NewLine + "Timed Out after waiting " + secondsBeforeTimeOut + " seconds.";
result.ExitCode = ProcessStream.kTimedOut;
+ activity?.SetStatus(ActivityStatusCode.Error, "Timeout");
}
else if (progress.CancelRequested)
{
result.StandardError += Environment.NewLine + "User Cancelled.";
result.ExitCode = ProcessStream.kCancelled;
+ activity?.SetStatus(ActivityStatusCode.Error, "User Cancelled");
}
else
{
result.ExitCode = process.ExitCode;
+ activity?.SetTag("app.hg.exit-code", result.ExitCode);
}
return result;
}
diff --git a/src/LibChorus/sync/Synchronizer.cs b/src/LibChorus/sync/Synchronizer.cs
index 01786db2..c2173e30 100644
--- a/src/LibChorus/sync/Synchronizer.cs
+++ b/src/LibChorus/sync/Synchronizer.cs
@@ -104,6 +104,8 @@ public static Synchronizer FromProjectConfiguration(ProjectFolderConfiguration p
public SyncResults SyncNow(SyncOptions options)
{
+ using var activity = LibChorusActivitySource.Value.StartActivity();
+
SyncResults results = new SyncResults();
List sourcesToTry = options.RepositorySourcesToTry;
// this saves us from trying to connect twice to the same repo that is, for example, not there.
@@ -156,12 +158,14 @@ public SyncResults SyncNow(SyncOptions options)
error.DoNotifications(Repository, _progress);
results.Succeeded = false;
results.ErrorEncountered = error;
+ activity?.AddException(error);
}
catch (UserCancelledException)
{
results.Succeeded = false;
results.Cancelled = true;
results.ErrorEncountered = null;
+ activity?.SetTag("app.chorus.sync.cancelled", true);
}
catch (Exception error)
{
@@ -178,6 +182,7 @@ public SyncResults SyncNow(SyncOptions options)
results.Succeeded = false;
results.ErrorEncountered = error;
+ activity?.AddException(error);
}
finally
{
@@ -245,6 +250,7 @@ public void SetIsOneOfDefaultSyncAddresses(RepositoryAddress address, bool enabl
private void SendToOthers(HgRepository repo, List sourcesToTry, Dictionary connectionAttempt)
{
+ using var activity = LibChorusActivitySource.Value.StartActivity();
foreach (RepositoryAddress address in sourcesToTry)
{
ThrowIfCancelPending();
@@ -325,6 +331,7 @@ private void SendToOneOther(RepositoryAddress address, Dictionarytrue if there was at least one successful pull
private bool PullFromOthers(HgRepository repo, List sourcesToTry, Dictionary connectionAttempt)
{
+ using var activity = LibChorusActivitySource.Value.StartActivity();
bool didGetFromAtLeastOneSource = false;
foreach (RepositoryAddress source in new List(sourcesToTry)) // LT-18276: apparently possible to modify sourcesToTry
{
@@ -628,6 +635,7 @@ private void TryToMakeCloneForSource(RepositoryAddress repoDescriptor)
#region Merging
private void MergeHeadsOrRollbackAndThrow(HgRepository repo, Revision workingRevBeforeSync)
{
+ using var activity = LibChorusActivitySource.Value.StartActivity();
try
{
MergeHeads();
@@ -642,6 +650,7 @@ private void MergeHeadsOrRollbackAndThrow(HgRepository repo, Revision workingRev
_progress.WriteException(error);
_progress.WriteError("Rolling back...");
UpdateToTheDescendantRevision(repo, workingRevBeforeSync); //rollback
+ activity?.AddException(error);
throw;
}
}