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; } }