diff --git a/src/Durable/DurableController.cs b/src/Durable/DurableController.cs index 01e8ff7a..59015d23 100644 --- a/src/Durable/DurableController.cs +++ b/src/Durable/DurableController.cs @@ -109,6 +109,11 @@ public bool TryInvokeOrchestrationFunction(out Hashtable result) return true; } + public bool ShouldSuppressPipelineTraces() + { + return _durableFunctionInfo.Type == DurableFunctionType.ActivityFunction; + } + private static OrchestrationBindingInfo CreateOrchestrationBindingInfo(IList inputData) { // Quote from https://docs.microsoft.com/en-us/azure/azure-functions/durable-functions-bindings: diff --git a/src/Durable/DurableFunctionInfo.cs b/src/Durable/DurableFunctionInfo.cs index 91a0477f..a245ac67 100644 --- a/src/Durable/DurableFunctionInfo.cs +++ b/src/Durable/DurableFunctionInfo.cs @@ -19,7 +19,11 @@ public DurableFunctionInfo(DurableFunctionType type, string durableClientBinding public string DurableClientBindingName { get; } - public DurableFunctionType Type { get; } + public DurableFunctionType Type + { + get; + internal set; // for testing purposes only + } public bool ProvidesForcedDollarReturnValue => Type != DurableFunctionType.None; } diff --git a/src/PowerShell/PowerShellManager.cs b/src/PowerShell/PowerShellManager.cs index 13e07a8b..1790a4d3 100644 --- a/src/PowerShell/PowerShellManager.cs +++ b/src/PowerShell/PowerShellManager.cs @@ -216,7 +216,10 @@ public Hashtable InvokeFunction( SetInputBindingParameterValues(functionInfo, inputData, durableController, triggerMetadata, traceContext); stopwatch.OnCheckpoint(FunctionInvocationPerformanceStopwatch.Checkpoint.InputBindingValuesReady); - _pwsh.AddCommand("Microsoft.Azure.Functions.PowerShellWorker\\Trace-PipelineObject"); + if (!durableController.ShouldSuppressPipelineTraces()) + { + _pwsh.AddCommand("Microsoft.Azure.Functions.PowerShellWorker\\Trace-PipelineObject"); + } stopwatch.OnCheckpoint(FunctionInvocationPerformanceStopwatch.Checkpoint.InvokingFunctionCode); Logger.Log(isUserOnlyLog: false, LogLevel.Trace, CreateInvocationPerformanceReportMessage(functionInfo.FuncName, stopwatch)); diff --git a/test/Unit/Durable/DurableControllerTests.cs b/test/Unit/Durable/DurableControllerTests.cs index 091a59e2..68531f7c 100644 --- a/test/Unit/Durable/DurableControllerTests.cs +++ b/test/Unit/Durable/DurableControllerTests.cs @@ -231,6 +231,16 @@ internal void AddPipelineOutputIfNecessary_DoesNotAddDollarReturn_ForNonActivity Assert.False(result.ContainsKey(AzFunctionInfo.DollarReturn)); } + [Theory] + [InlineData(DurableFunctionType.None, false)] + [InlineData(DurableFunctionType.OrchestrationFunction, false)] + [InlineData(DurableFunctionType.ActivityFunction, true)] + internal void SuppressPipelineTracesForActivityFunctionOnly(DurableFunctionType durableFunctionType, bool shouldSuppressPipelineTraces) + { + var durableController = CreateDurableController(durableFunctionType); + Assert.Equal(shouldSuppressPipelineTraces, durableController.ShouldSuppressPipelineTraces()); + } + private DurableController CreateDurableController( DurableFunctionType durableFunctionType, string durableClientBindingName = null) diff --git a/test/Unit/PowerShell/PowerShellManagerTests.cs b/test/Unit/PowerShell/PowerShellManagerTests.cs index 8c4e3921..7fb062aa 100644 --- a/test/Unit/PowerShell/PowerShellManagerTests.cs +++ b/test/Unit/PowerShell/PowerShellManagerTests.cs @@ -17,6 +17,8 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Test { using System.Collections.ObjectModel; using System.Management.Automation; + using Microsoft.Azure.Functions.PowerShellWorker.Durable; + using Newtonsoft.Json; internal class TestUtils { @@ -373,6 +375,52 @@ public void LoggerContextIsSet() powerShellManagerPool.ReclaimUsedWorker(worker); } + [Theory] + [InlineData(DurableFunctionType.None, false)] + [InlineData(DurableFunctionType.OrchestrationFunction, false)] + [InlineData(DurableFunctionType.ActivityFunction, true)] + internal void SuppressPipelineTracesForDurableActivityFunctionOnly(DurableFunctionType durableFunctionType, bool shouldSuppressPipelineTraces) + { + s_testLogger.FullLog.Clear(); + + var path = Path.Join(s_funcDirectory, "testFunctionWithOutput.ps1"); + var (functionInfo, testManager) = PrepareFunction(path, string.Empty); + functionInfo.DurableFunctionInfo.Type = durableFunctionType; + + try + { + FunctionMetadata.RegisterFunctionMetadata(testManager.InstanceId, functionInfo.OutputBindings); + + var result = testManager.InvokeFunction(functionInfo, null, null, CreateOrchestratorInputData(), new FunctionInvocationPerformanceStopwatch()); + + var relevantLogs = s_testLogger.FullLog.Where(message => message.StartsWith("Information: OUTPUT:")).ToList(); + var expected = shouldSuppressPipelineTraces ? new string[0] : new[] { "Information: OUTPUT: Hello" }; + Assert.Equal(expected, relevantLogs); + } + finally + { + FunctionMetadata.UnregisterFunctionMetadata(testManager.InstanceId); + } + } + + private static List CreateOrchestratorInputData() + { + var orchestrationContext = new OrchestrationContext + { + History = new[] { new HistoryEvent { EventType = HistoryEventType.OrchestratorStarted } } + }; + + var testInputData = new List + { + new ParameterBinding + { + Name = TestInputBindingName, + Data = new TypedData { String = JsonConvert.SerializeObject(orchestrationContext) } + } + }; + return testInputData; + } + private static Hashtable InvokeFunction(PowerShellManager powerShellManager, AzFunctionInfo functionInfo, Hashtable triggerMetadata = null) { return powerShellManager.InvokeFunction(functionInfo, triggerMetadata, null, s_testInputData, new FunctionInvocationPerformanceStopwatch()); diff --git a/test/Unit/PowerShell/TestScripts/testFunctionWithOutput.ps1 b/test/Unit/PowerShell/TestScripts/testFunctionWithOutput.ps1 new file mode 100644 index 00000000..d85064ca --- /dev/null +++ b/test/Unit/PowerShell/TestScripts/testFunctionWithOutput.ps1 @@ -0,0 +1,8 @@ +# +# Copyright (c) Microsoft. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project root for full license information. +# + +param ($Req) + +'Hello'