mirror of https://github.com/dapr/dotnet-sdk.git
Initial implementation for workflow log tracing (#1176)
* Initial setup for workflow log tracing Signed-off-by: Ryan Lettieri <ryanLettieri@microsoft.com> * Created log sink for E2E tests using serilog Signed-off-by: Ryan Lettieri <ryanLettieri@microsoft.com> * Formatting Signed-off-by: Ryan Lettieri <ryanLettieri@microsoft.com> * Addressing feedback on review Signed-off-by: Ryan Lettieri <ryanLettieri@microsoft.com> * Addressing some review comments Signed-off-by: Ryan Lettieri <ryanLettieri@microsoft.com> * Addressing more feedbck in the workflow e2e test Signed-off-by: Ryan Lettieri <ryanLettieri@microsoft.com> --------- Signed-off-by: Ryan Lettieri <ryanLettieri@microsoft.com>
This commit is contained in:
parent
2332388155
commit
39a38f6e9b
|
@ -0,0 +1,75 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2022 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
namespace Dapr.Workflow
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Defines runtime options for workflows.
|
||||
/// </summary>
|
||||
internal sealed class WorkflowLoggingService : IHostedService
|
||||
{
|
||||
private readonly ILogger<WorkflowLoggingService> logger;
|
||||
private static readonly HashSet<string> registeredWorkflows = new();
|
||||
private static readonly HashSet<string> registeredActivities = new();
|
||||
|
||||
public WorkflowLoggingService(ILogger<WorkflowLoggingService> logger, IConfiguration configuration)
|
||||
{
|
||||
this.logger = logger;
|
||||
|
||||
}
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
this.logger.Log(LogLevel.Information, "WorkflowLoggingService started");
|
||||
|
||||
this.logger.Log(LogLevel.Information, "List of registered workflows");
|
||||
foreach (string item in registeredWorkflows)
|
||||
{
|
||||
this.logger.Log(LogLevel.Information, item);
|
||||
}
|
||||
|
||||
this.logger.Log(LogLevel.Information, "List of registered activities:");
|
||||
foreach (string item in registeredActivities)
|
||||
{
|
||||
this.logger.Log(LogLevel.Information, item);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
this.logger.Log(LogLevel.Information, "WorkflowLoggingService stopped");
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public static void LogWorkflowName(string workflowName)
|
||||
{
|
||||
registeredWorkflows.Add(workflowName);
|
||||
}
|
||||
|
||||
public static void LogActivityName(string activityName)
|
||||
{
|
||||
registeredActivities.Add(activityName);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -54,6 +54,7 @@ namespace Dapr.Workflow
|
|||
WorkflowContext workflowContext = new DaprWorkflowContext(innerContext);
|
||||
return implementation(workflowContext, input);
|
||||
});
|
||||
WorkflowLoggingService.LogWorkflowName(name);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -73,6 +74,7 @@ namespace Dapr.Workflow
|
|||
TWorkflow workflow = Activator.CreateInstance<TWorkflow>();
|
||||
return new OrchestratorWrapper(workflow);
|
||||
});
|
||||
WorkflowLoggingService.LogWorkflowName(name);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -91,6 +93,7 @@ namespace Dapr.Workflow
|
|||
WorkflowActivityContext activityContext = new(innerContext);
|
||||
return implementation(activityContext, input);
|
||||
});
|
||||
WorkflowLoggingService.LogActivityName(name);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -111,6 +114,7 @@ namespace Dapr.Workflow
|
|||
TActivity activity = ActivatorUtilities.CreateInstance<TActivity>(serviceProvider);
|
||||
return new ActivityWrapper(activity);
|
||||
});
|
||||
WorkflowLoggingService.LogActivityName(name);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace Dapr.Workflow
|
|||
#pragma warning disable CS0618 // Type or member is obsolete - keeping around temporarily - replaced by DaprWorkflowClient
|
||||
serviceCollection.TryAddSingleton<WorkflowEngineClient>();
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
serviceCollection.AddHostedService<WorkflowLoggingService>();
|
||||
serviceCollection.TryAddSingleton<DaprWorkflowClient>();
|
||||
serviceCollection.AddDaprClient();
|
||||
serviceCollection.AddDaprWorkflowClient();
|
||||
|
|
|
@ -10,4 +10,11 @@
|
|||
<ProjectReference Include="..\Dapr.E2E.Test.Actors\Dapr.E2E.Test.Actors.csproj" />
|
||||
<ProjectReference Include="..\..\src\Dapr.Workflow\Dapr.Workflow.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Serilog" Version="3.0.1" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2021 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
// Copyright 2021 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
namespace Dapr.E2E.Test
|
||||
{
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Serilog;
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Log.Logger = new LoggerConfiguration().WriteTo.File("log.txt").CreateLogger();
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
|
@ -26,6 +28,6 @@ namespace Dapr.E2E.Test
|
|||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
}).UseSerilog();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@ namespace Dapr.E2E.Test
|
|||
using Microsoft.Extensions.Hosting;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Serilog;
|
||||
|
||||
/// <summary>
|
||||
/// Startup class.
|
||||
|
@ -61,6 +63,10 @@ namespace Dapr.E2E.Test
|
|||
services.AddAuthentication().AddDapr();
|
||||
services.AddAuthorization(o => o.AddDapr());
|
||||
services.AddControllers().AddDapr();
|
||||
services.AddLogging(builder =>
|
||||
{
|
||||
builder.AddConsole();
|
||||
});
|
||||
// Register a workflow and associated activity
|
||||
services.AddDaprWorkflow(options =>
|
||||
{
|
||||
|
@ -108,11 +114,19 @@ namespace Dapr.E2E.Test
|
|||
/// <param name="env">Webhost environment.</param>
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
var logger = new LoggerConfiguration().WriteTo.File("log.txt").CreateLogger();
|
||||
|
||||
var loggerFactory = LoggerFactory.Create(builder =>
|
||||
{
|
||||
builder.AddSerilog(logger);
|
||||
});
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.UseSerilogRequestLogging();
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
app.UseAuthentication();
|
||||
|
|
|
@ -11,25 +11,81 @@
|
|||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Dapr.Client;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Dapr.E2E.Test
|
||||
{
|
||||
[Obsolete]
|
||||
public partial class E2ETests
|
||||
{
|
||||
[Fact]
|
||||
public async Task TestWorkflowLogging()
|
||||
{
|
||||
// This test starts the daprclient and searches through the logfile to ensure the
|
||||
// workflow logger is correctly logging the registered workflow(s) and activity(s)
|
||||
|
||||
Dictionary<string, bool> logStrings = new Dictionary<string, bool>();
|
||||
logStrings["PlaceOrder"] = false;
|
||||
logStrings["ShipProduct"] = false;
|
||||
var logFilePath = "../../../../../test/Dapr.E2E.Test.App/log.txt";
|
||||
var allLogsFound = false;
|
||||
var timeout = 30; // 30s
|
||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(timeout));
|
||||
using var daprClient = new DaprClientBuilder().UseGrpcEndpoint(this.GrpcEndpoint).UseHttpEndpoint(this.HttpEndpoint).Build();
|
||||
var health = await daprClient.CheckHealthAsync();
|
||||
health.Should().Be(true, "DaprClient is not healthy");
|
||||
|
||||
var searchTask = Task.Run(async() =>
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(logFilePath))
|
||||
{
|
||||
string line;
|
||||
while ((line = await reader.ReadLineAsync().WaitAsync(cts.Token)) != null)
|
||||
{
|
||||
foreach (var entry in logStrings)
|
||||
{
|
||||
if (line.Contains(entry.Key))
|
||||
{
|
||||
logStrings[entry.Key] = true;
|
||||
}
|
||||
}
|
||||
allLogsFound = logStrings.All(k => k.Value);
|
||||
if (allLogsFound)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, cts.Token);
|
||||
|
||||
try
|
||||
{
|
||||
await searchTask;
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(logFilePath);
|
||||
}
|
||||
if (!allLogsFound)
|
||||
{
|
||||
Assert.True(false, "The logs were not able to found within the timeout");
|
||||
}
|
||||
}
|
||||
[Fact]
|
||||
public async Task TestWorkflows()
|
||||
{
|
||||
string instanceId = "testInstanceId";
|
||||
string instanceId2 = "EventRaiseId";
|
||||
string workflowComponent = "dapr";
|
||||
string workflowName = "PlaceOrder";
|
||||
var instanceId = "testInstanceId";
|
||||
var instanceId2 = "EventRaiseId";
|
||||
var workflowComponent = "dapr";
|
||||
var workflowName = "PlaceOrder";
|
||||
object input = "paperclips";
|
||||
Dictionary<string, string> workflowOptions = new Dictionary<string, string>();
|
||||
workflowOptions.Add("task_queue", "testQueue");
|
||||
|
|
Loading…
Reference in New Issue