Diagnostics source
This page is part of the documentation for Orleans.Lattice 9.9.0 (release line 9.9), built 2026-10-04. It is also published as markdown, with every table and list, at source.md, and llms.txt lists every page.The source of the Diagnostics sample.
Program.cs
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Orleans.Hosting;
using Orleans.Lattice;
// Diagnostics sample
// ==================
// ILattice.DiagnoseAsync returns a point-in-time health snapshot of a tree:
// shard count, live keys, tombstones, B+ tree depth per shard, and per-shard
// hotness (ops/second). It is an admin-rate API for dashboards, health probes,
// and post-mortem investigation - not for hot-path application logic.
//
// This sample writes some keys, deletes a few (leaving tombstones), then prints
// a deep diagnostic report (deep: true counts tombstones exactly).
using var host = Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.None);
})
.UseOrleans(silo =>
{
silo.UseLocalhostClustering();
silo.AddMemoryGrainStorageAsDefault();
silo.UseInMemoryReminderService();
silo.AddLattice((s, name) => s.AddMemoryGrainStorage(name));
})
.Build();
Console.Write("Silo starting...");
await host.StartAsync();
Console.WriteLine(" ready.");
Console.WriteLine();
var grains = host.Services.GetRequiredService<IGrainFactory>();
var tree = grains.GetGrain<ILattice>("inventory");
// Populate the tree, then delete a couple of keys to leave tombstones behind.
Console.WriteLine("Writing 10 keys, then deleting 3 (leaving tombstones)...");
for (var i = 0; i < 10; i++)
{
await tree.SetAsync($"item-{i:D2}", Encoding.UTF8.GetBytes($"qty-{i}"));
}
await tree.DeleteAsync("item-00");
await tree.DeleteAsync("item-03");
await tree.DeleteAsync("item-07");
Console.WriteLine();
// A deep report walks each shard's leaf chain to count tombstones exactly.
var report = await tree.DiagnoseAsync(deep: true, CancellationToken.None);
Console.WriteLine($"Tree '{report.TreeId}' health snapshot (sampled {report.SampledAt:O}):");
Console.WriteLine($" Deep report: {report.Deep}");
Console.WriteLine($" Shard count: {report.ShardCount} (of {report.VirtualShardCount} virtual slots)");
Console.WriteLine($" Total live keys: {report.TotalLiveKeys}");
Console.WriteLine($" Total tombstones: {report.TotalTombstones}");
Console.WriteLine($" Recent splits: {report.RecentSplits.Length}");
Console.WriteLine();
Console.WriteLine("Per-shard breakdown (shards with activity only):");
foreach (var shard in report.Shards)
{
if (shard.LiveKeys == 0 && shard.Tombstones == 0 && shard.Writes == 0 && shard.Reads == 0)
{
continue;
}
Console.WriteLine(
$" shard {shard.ShardIndex}: depth={shard.Depth} rootIsLeaf={shard.RootIsLeaf} " +
$"live={shard.LiveKeys} tombstones={shard.Tombstones} " +
$"ratio={shard.TombstoneRatio:F2} reads={shard.Reads} writes={shard.Writes} " +
$"ops/s={shard.OpsPerSecond:F1}");
}
await host.StopAsync();
Diagnostics.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>Orleans.Lattice.Samples.Diagnostics</RootNamespace>
<AssemblyName>Orleans.Lattice.Samples.Diagnostics</AssemblyName>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.11" />
<PackageReference Include="Microsoft.Orleans.Server" Version="10.2.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\lattice\Orleans.Lattice.csproj" />
</ItemGroup>
</Project>