Source Generator Observability
A practical guide to auto-generating logging, tracing, and metrics code with the C# Roslyn API
About This Tutorial
Section titled “About This Tutorial”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.
Target Audience
Section titled “Target Audience”| Level | Audience | Recommended Scope |
|---|---|---|
| Beginner | Developers who know basic C# syntax but are new to Source Generators | Parts 0—1 |
| Intermediate | Developers without Roslyn API experience | All of Part 2 |
| Advanced | Developers who want to automate repetitive boilerplate code | Parts 3—4 + Appendix |
Learning Objectives
Section titled “Learning Objectives”After completing this tutorial, you will be able to:
- Understand the architecture and operating principles of the Roslyn compiler platform
- Develop Source Generators implementing the IIncrementalGenerator interface
- Extract code metadata through symbol analysis
- Apply deterministic code generation techniques
- Write Source Generator unit tests
Part 0: Introduction
Section titled “Part 0: Introduction”Understand the concept and necessity of Source Generators.
- 0.1 What Is a Source Generator?
- 0.2 Hello World Generator
- 0.3 Why Source Generators Are Needed
- 0.4 Reflection vs Source Generator
- 0.5 Project Overview
Part 1: Fundamentals
Section titled “Part 1: Fundamentals”Set up the development environment and understand the Roslyn compiler platform.
| Ch | Topic | Key Learning |
|---|---|---|
| 1 | Development Environment | Development environment setup |
| 2 | Project Structure | Source Generator project configuration |
| 3 | Debugging Setup | Debugging environment setup |
| 4 | Roslyn Architecture | Compiler platform architecture |
| 5 | Syntax API | Syntax tree analysis |
| 6 | Semantic API | Semantic analysis |
| 7 | Symbol Types | Understanding Symbol types |
Part 2: Core Concepts
Section titled “Part 2: Core Concepts”Learn Incremental Source Generator implementation and code generation techniques.
| Ch | Topic | Key Learning |
|---|---|---|
| 1 | IIncrementalGenerator Interface | Incremental Generator interface |
| 2 | Provider Pattern | Data Provider Pattern |
| 3 | ForAttributeWithMetadataName | Attribute-based filtering |
| 4 | Incremental Caching | Performance optimization |
| 5 | INamedTypeSymbol | Type Symbol analysis |
| 6 | IMethodSymbol | Method Symbol analysis |
| 7 | SymbolDisplayFormat | Symbol display format |
| 8 | Type Extraction | Extracting type information |
| 9 | StringBuilder Pattern | Basic code generation |
| 10 | Template Design | Structuring code templates |
| 11 | Namespace Handling | Namespace management |
| 12 | Deterministic Output | Deterministic code generation |
Part 3: Advanced
Section titled “Part 3: Advanced”Learn complex case handling and testing strategies.
| Ch | Topic | Key Learning |
|---|---|---|
| 1 | Constructor Handling | Constructor analysis and generation |
| 2 | Generic Types | Generic type handling |
| 3 | Collection Types | Collection type handling |
| 4 | LoggerMessage.Define Limitations | Logger message constraints |
| 5 | Unit Test Setup | Test environment setup |
| 6 | Verify Snapshot Testing | Snapshot testing |
| 7 | Test Scenarios | Writing test cases |
Part 4: Cookbook
Section titled “Part 4: Cookbook”Learn Source Generator development procedures through various practical examples.
| Ch | Topic | Key Learning |
|---|---|---|
| 1 | Source Generator Development Workflow | Development workflow overview |
| 2 | Entity ID Generator | DDD strongly-typed ID (Ulid-based) |
| 3 | EF Core Value Converter | Auto-generating ValueConverters |
| 4 | Validation Generator | FluentValidation rule generation |
| 5 | Custom Generator Template | Guide to starting a new project |
Part 5: Conclusion
Section titled “Part 5: Conclusion”Summarize the content and provide guidance for next steps.
Core Evolution Process
Section titled “Core Evolution Process”[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
Hands-On Project: ObservablePortGenerator
Section titled “Hands-On Project: ObservablePortGenerator”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 includedpublic class UserRepositoryObservable : UserRepository{ // Logging, tracing, and metrics automatically applied to all methods}Prerequisites
Section titled “Prerequisites”- .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
Project Structure
Section titled “Project Structure”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.mdTesting
Section titled “Testing”All example projects in every Part include unit tests. Tests follow the Unit Testing Guide.
Running Tests
Section titled “Running Tests”# Build the entire tutorialdotnet build sourcegen-observability.slnx
# Test the entire tutorialdotnet test --solution sourcegen-observability.slnxTest Project Structure
Section titled “Test Project Structure”Part 4: Cookbook (5)
| Ch | Test Project | Key Test Content |
|---|---|---|
| 1 | DevelopmentWorkflow.Tests.Unit | Source Generator development workflow verification |
| 2 | EntityIdGenerator.Tests.Unit | DDD strongly-typed ID (Ulid-based) generation |
| 3 | EfCoreValueConverter.Tests.Unit | ValueConverter auto-generation verification |
| 4 | ValidationGenerator.Tests.Unit | FluentValidation rule generation verification |
| 5 | CustomGeneratorTemplate.Tests.Unit | Custom Generator template verification |
Test Naming Convention
Section titled “Test Naming Convention”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();}Source Code
Section titled “Source Code”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.