Skip to content

Source Generator Observability

A practical guide to auto-generating logging, tracing, and metrics code with the C# Roslyn API


If you are copy-pasting logging, tracing, and metrics code into every Repository method by hand, a Source Generator can put an end to that repetitive work.

This tutorial guides you from learning C# Source Generators from scratch to using them in production. Starting from the fundamentals of the Roslyn compiler platform, you will learn high-performance Source Generator development using the IIncrementalGenerator pattern step by step.

Automate repetitive boilerplate code and build a Source Generator that guarantees 100% consistent observability.

LevelAudienceRecommended Scope
BeginnerDevelopers who know basic C# syntax but are new to Source GeneratorsParts 0—1
IntermediateDevelopers without Roslyn API experienceAll of Part 2
AdvancedDevelopers who want to automate repetitive boilerplate codeParts 3—4 + Appendix

After completing this tutorial, you will be able to:

  1. Understand the architecture and operating principles of the Roslyn compiler platform
  2. Develop Source Generators implementing the IIncrementalGenerator interface
  3. Extract code metadata through symbol analysis
  4. Apply deterministic code generation techniques
  5. Write Source Generator unit tests

Understand the concept and necessity of Source Generators.

Set up the development environment and understand the Roslyn compiler platform.

ChTopicKey Learning
1Development EnvironmentDevelopment environment setup
2Project StructureSource Generator project configuration
3Debugging SetupDebugging environment setup
4Roslyn ArchitectureCompiler platform architecture
5Syntax APISyntax tree analysis
6Semantic APISemantic analysis
7Symbol TypesUnderstanding Symbol types

Learn Incremental Source Generator implementation and code generation techniques.

ChTopicKey Learning
1IIncrementalGenerator InterfaceIncremental Generator interface
2Provider PatternData Provider Pattern
3ForAttributeWithMetadataNameAttribute-based filtering
4Incremental CachingPerformance optimization
5INamedTypeSymbolType Symbol analysis
6IMethodSymbolMethod Symbol analysis
7SymbolDisplayFormatSymbol display format
8Type ExtractionExtracting type information
9StringBuilder PatternBasic code generation
10Template DesignStructuring code templates
11Namespace HandlingNamespace management
12Deterministic OutputDeterministic code generation

Learn complex case handling and testing strategies.

ChTopicKey Learning
1Constructor HandlingConstructor analysis and generation
2Generic TypesGeneric type handling
3Collection TypesCollection type handling
4LoggerMessage.Define LimitationsLogger message constraints
5Unit Test SetupTest environment setup
6Verify Snapshot TestingSnapshot testing
7Test ScenariosWriting test cases

Learn Source Generator development procedures through various practical examples.

ChTopicKey Learning
1Source Generator Development WorkflowDevelopment workflow overview
2Entity ID GeneratorDDD strongly-typed ID (Ulid-based)
3EF Core Value ConverterAuto-generating ValueConverters
4Validation GeneratorFluentValidation rule generation
5Custom Generator TemplateGuide to starting a new project

Summarize the content and provide guidance for next steps.


[Part 1] Fundamentals Ch 1: Development Environment -> Ch 2: Project Structure -> Ch 3: Debugging Setup -> Ch 4: Roslyn Architecture -> Ch 5: Syntax API -> Ch 6: Semantic API -> Ch 7: Symbol Types

[Part 2] Core Concepts Ch 1: IIncrementalGenerator Interface -> Ch 2: Provider Pattern -> Ch 3: ForAttributeWithMetadataName -> Ch 4: Incremental Caching -> Ch 5: INamedTypeSymbol -> Ch 6: IMethodSymbol -> Ch 7: SymbolDisplayFormat -> Ch 8: Type Extraction -> Ch 9: StringBuilder Pattern -> Ch 10: Template Design -> Ch 11: Namespace Handling -> Ch 12: Deterministic Output

[Part 3] Advanced Ch 1: Constructor Handling -> Ch 2: Generic Types -> Ch 3: Collection Types -> Ch 4: LoggerMessage.Define Limitations -> Ch 5: Unit Test Setup -> Ch 6: Verify Snapshot Testing -> Ch 7: Test Scenarios

[Part 4] Cookbook Ch 1: Source Generator Development Workflow -> Ch 2: Entity ID Generator -> Ch 3: EF Core Value Converter -> Ch 4: Validation Generator -> Ch 5: Custom Generator Template


In this tutorial, you will implement an actual Source Generator called ObservablePortGenerator step by step. For details on the project’s design goals, structure, and expected benefits, see Part 0-05. Project Overview.

// Code the developer writes -- focus only on business logic
[GenerateObservablePort]
public class UserRepository(ILogger<UserRepository> logger) : IObservablePort
{
public FinT<IO, User> GetUserAsync(int id) => /* pure logic */;
}
// Auto-generated by the Source Generator -- observability code included
public class UserRepositoryObservable : UserRepository
{
// Logging, tracing, and metrics automatically applied to all methods
}

  • .NET 10.0 SDK (Preview or release version)
  • Visual Studio 2022 (17.12 or later) or VS Code (C# Dev Kit extension)
  • Basic knowledge of C# 14 syntax

sourcegen-observability/
├── Part0-Introduction/ # Part 0: Introduction
│ ├── 01-what-is-source-generator.md
│ ├── 02-hello-world-generator/
│ ├── 03-why-source-generator.md
│ ├── 04-reflection-vs-sourcegen/
│ └── 05-project-overview.md
├── Part1-Fundamentals/ # Part 1: Fundamentals
│ ├── 01-development-environment.md
│ ├── 02-Data-Models/
│ ├── 03-Debugging-Setup/
│ ├── ...
│ └── 07-Symbol-Types/
├── Part2-Core-Concepts/ # Part 2: Core Concepts
│ ├── 01-IIncrementalGenerator/
│ ├── ...
│ └── 12-Deterministic-Output/
├── Part3-Advanced/ # Part 3: Advanced
│ ├── 01-Constructor-Handling/
│ ├── ...
│ └── 07-Test-Scenarios/
├── Part4-Cookbook/ # Part 4: Cookbook
│ ├── 01-Development-Workflow/
│ ├── ...
│ └── 05-Custom-Generator-Template/
├── Part5-Conclusion/ # Part 5: Conclusion
│ ├── 01-summary.md
│ └── 02-next-steps.md
└── Appendix/ # Appendix
├── A-development-environment.md
├── B-api-reference.md
├── C-test-scenario-catalog.md
└── D-troubleshooting.md

All example projects in every Part include unit tests. Tests follow the Unit Testing Guide.

Terminal window
# Build the entire tutorial
dotnet build sourcegen-observability.slnx
# Test the entire tutorial
dotnet test --solution sourcegen-observability.slnx

Part 4: Cookbook (5)

ChTest ProjectKey Test Content
1DevelopmentWorkflow.Tests.UnitSource Generator development workflow verification
2EntityIdGenerator.Tests.UnitDDD strongly-typed ID (Ulid-based) generation
3EfCoreValueConverter.Tests.UnitValueConverter auto-generation verification
4ValidationGenerator.Tests.UnitFluentValidation rule generation verification
5CustomGeneratorTemplate.Tests.UnitCustom Generator template verification

Follows the T1_T2_T3 naming convention:

// Method_ExpectedResult_Scenario
[Fact]
public void Generate_ProducesExpectedOutput_WhenClassHasObservablePortAttribute()
{
// Arrange
var source = /* input source code */;
// Act
var actual = GeneratorTestHelper.RunGenerator(source);
// Assert
actual.ShouldMatchExpected();
}

All example code for this tutorial can be found in the Functorium project:

  • Source Generators: Src/Functorium.SourceGenerators/
  • Adapters (attributes, naming): Src/Functorium.Adapters/
  • Tests: Tests/Functorium.Tests.Unit/AdaptersTests/SourceGenerators/
  • Test utilities: Src/Functorium.Testing/Actions/SourceGenerators/

This tutorial was written based on real-world experience developing Source Generators in the Functorium project.