diff --git a/samples/dapr/ServiceA/DaprServiceA.csproj b/samples/dapr/ServiceA/DaprServiceA.csproj
index db4fe8dab7c..7bb2583264f 100644
--- a/samples/dapr/ServiceA/DaprServiceA.csproj
+++ b/samples/dapr/ServiceA/DaprServiceA.csproj
@@ -12,4 +12,8 @@
+
+
+
+
diff --git a/samples/dapr/ServiceA/Program.cs b/samples/dapr/ServiceA/Program.cs
index b3fe47699f3..78d800cad97 100644
--- a/samples/dapr/ServiceA/Program.cs
+++ b/samples/dapr/ServiceA/Program.cs
@@ -5,6 +5,8 @@
var builder = WebApplication.CreateBuilder(args);
+builder.AddServiceDefaults();
+
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
diff --git a/samples/dapr/ServiceB/DaprServiceB.csproj b/samples/dapr/ServiceB/DaprServiceB.csproj
index db4fe8dab7c..7bb2583264f 100644
--- a/samples/dapr/ServiceB/DaprServiceB.csproj
+++ b/samples/dapr/ServiceB/DaprServiceB.csproj
@@ -12,4 +12,8 @@
+
+
+
+
diff --git a/samples/dapr/ServiceB/Program.cs b/samples/dapr/ServiceB/Program.cs
index 43d9a74f39d..642612f1b82 100644
--- a/samples/dapr/ServiceB/Program.cs
+++ b/samples/dapr/ServiceB/Program.cs
@@ -3,6 +3,8 @@
var builder = WebApplication.CreateBuilder(args);
+builder.AddServiceDefaults();
+
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
diff --git a/src/Aspire.Dashboard/Otlp/Model/OtlpApplication.cs b/src/Aspire.Dashboard/Otlp/Model/OtlpApplication.cs
index 943c1bf6fb6..be34c0ad031 100644
--- a/src/Aspire.Dashboard/Otlp/Model/OtlpApplication.cs
+++ b/src/Aspire.Dashboard/Otlp/Model/OtlpApplication.cs
@@ -53,7 +53,11 @@ public OtlpApplication(Resource resource, IReadOnlyDictionary a.Value.ApplicationName == ApplicationName).Count();
_logger = logger;
diff --git a/src/Aspire.Dashboard/Otlp/Model/OtlpHelpers.cs b/src/Aspire.Dashboard/Otlp/Model/OtlpHelpers.cs
index dd6fc0bd51f..416405a44cc 100644
--- a/src/Aspire.Dashboard/Otlp/Model/OtlpHelpers.cs
+++ b/src/Aspire.Dashboard/Otlp/Model/OtlpHelpers.cs
@@ -16,6 +16,8 @@ public static class OtlpHelpers
{
public static string? GetServiceId(this Resource resource)
{
+ string? serviceName = null;
+
for (var i = 0; i < resource.Attributes.Count; i++)
{
var attribute = resource.Attributes[i];
@@ -23,9 +25,17 @@ public static class OtlpHelpers
{
return attribute.Value.GetString();
}
+ if (attribute.Key == OtlpApplication.SERVICE_NAME)
+ {
+ serviceName = attribute.Value.GetString();
+ }
}
- return null;
+ //
+ // NOTE: The service.instance.id value is a recommended attribute, but not required.
+ // See: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#service-experimental
+ //
+ return serviceName;
}
public static string ToShortenedId(string id) =>
diff --git a/src/Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs b/src/Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs
index 74cc34eee59..b0805ec646d 100644
--- a/src/Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs
+++ b/src/Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs
@@ -3,6 +3,7 @@
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Lifecycle;
+using Microsoft.Extensions.Configuration;
using System.Globalization;
using System.Net.Sockets;
using static Aspire.Hosting.Dapr.CommandLineArgs;
@@ -11,6 +12,7 @@ namespace Aspire.Hosting.Dapr;
internal sealed class DaprDistributedApplicationLifecycleHook : IDistributedApplicationLifecycleHook
{
+ private readonly IConfiguration _configuration;
private readonly DaprOptions _options;
private readonly DaprPortManager _portManager;
@@ -20,9 +22,12 @@ internal sealed class DaprDistributedApplicationLifecycleHook : IDistributedAppl
: Path.Combine("/usr", "local", "bin", "dapr");
private const int DaprHttpPortStartRange = 50001;
+ private const string DashboardOtlpUrlVariableName = "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL";
+ private const string DashboardOtlpUrlDefaultValue = "http://localhost:18889";
- public DaprDistributedApplicationLifecycleHook(DaprOptions options, DaprPortManager portManager)
+ public DaprDistributedApplicationLifecycleHook(IConfiguration configuration, DaprOptions options, DaprPortManager portManager)
{
+ _configuration = configuration;
this._options = options;
this._portManager = portManager;
}
@@ -126,6 +131,27 @@ public Task BeforeStartAsync(DistributedApplicationModel appModel, CancellationT
component.Annotations.Add(new NameAnnotation { Name = sidecarOptions?.AppId ?? "Unknown" });
component.Annotations.AddRange(ports.Select(port => new ServiceBindingAnnotation(ProtocolType.Tcp, name: port.Key, port: port.Value.Port)));
+ // NOTE: Telemetry is enabled by default.
+ if (this._options.EnableTelemetry != false)
+ {
+ component.Annotations.Add(
+ new EnvironmentCallbackAnnotation(
+ env =>
+ {
+
+ //
+ // NOTE: Setting OTEL_EXPORTER_OTLP_ENDPOINT will not override any explicit OTLP configuration in a specified Dapr sidecar configuration file.
+ // The ambient Dapr sidecar configuration file does not configure an OTLP exporter (but could have been updated by the user to do so).
+ //
+ // TODO: It would be nice, at some point, to consolidate determination of the OTLP endpoint as it's now repeated in a few places.
+ //
+
+ env["OTEL_EXPORTER_OTLP_ENDPOINT"] = this._configuration[DashboardOtlpUrlVariableName] ?? DashboardOtlpUrlDefaultValue;
+ env["OTEL_EXPORTER_OTLP_INSECURE"] = "true";
+ env["OTEL_EXPORTER_OTLP_PROTOCOL"] = "grpc";
+ }));
+ }
+
component.Annotations.Add(
new ExecutableArgsCallbackAnnotation(
updatedArgs =>
diff --git a/src/Aspire.Hosting.Dapr/DaprOptions.cs b/src/Aspire.Hosting.Dapr/DaprOptions.cs
index b4f871c35af..e1726471991 100644
--- a/src/Aspire.Hosting.Dapr/DaprOptions.cs
+++ b/src/Aspire.Hosting.Dapr/DaprOptions.cs
@@ -12,4 +12,12 @@ public sealed record DaprOptions
/// Gets or sets the path to the Dapr CLI.
///
public string? DaprPath { get; init; }
+
+ ///
+ /// Gets or sets whether Dapr sidecars export telemetry to the Aspire dashboard.
+ ///
+ ///
+ /// Telemetry is enabled by default.
+ ///
+ public bool? EnableTelemetry { get; init; }
}