Skip to content

Commit 9a58f63

Browse files
lucaspimentelclaude
authored andcommitted
Add performance, testing, and logging guidelines to AGENTS.md (#7609)
## Summary of changes - Add performance optimization patterns, testing guidelines, and logging guidelines to `AGENTS.md`. - Bonus: Fix noop pipeline path exclusions to properly skip CI for documentation-only PRs. ## Reason for change **Documentation:** Document reusable patterns that apply broadly across the tracer codebase: - Performance patterns for startup code and hot paths (from PR #7594) - Testing patterns for testability and isolation (from PR #7594) - Logging terminology to avoid customer confusion (from PR #7467) **CI Optimization:** The noop pipeline was not triggering for documentation-only PRs because it uses `StartsWith()` matching, not glob patterns. The `**/CLAUDE.md` pattern never matched `.claude/CLAUDE.md`. ## Implementation details **New documentation sections:** - Performance Guidelines: Identifies performance-critical code paths (bootstrap/startup and hot paths) - Performance Optimization Patterns: Zero-allocation structs, logging best practices, avoiding params arrays - Testing Patterns: Abstraction-for-testability with examples - Logging Guidelines: Consistent customer-facing terminology (Datadog SDK, Instrumentation, Continuous Profiler, Datadog.Trace.dll) **Pipeline fixes:** - Changed `**/CLAUDE.md` glob to `.claude/` prefix (compatible with `StartsWith()`) - Added `.devcontainer/`, `.vscode/`, `LICENSE`, `NOTICE` to exclusions **Other changes:** - Fixed `.claude/CLAUDE.md` relative path reference - Improved formatting in Coding Style section ## Test coverage N/A - documentation and CI configuration only --------- Co-authored-by: Claude <[email protected]>
1 parent 9671f05 commit 9a58f63

File tree

3 files changed

+145
-7
lines changed

3 files changed

+145
-7
lines changed

.azure-pipelines/ultimate-pipeline.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,15 @@ pr:
2626
exclude:
2727
- .azure-pipelines/noop-pipeline.yml
2828
- .github/
29+
- .claude/
30+
- .devcontainer/
31+
- .vscode/
2932
- docs/
3033
- tracer/README.MD
3134
- tracer/samples/
3235
- AGENTS.md
33-
- '**/CLAUDE.md'
36+
- LICENSE
37+
- NOTICE
3438

3539
schedules:
3640
- cron: "0 3 * * *"

.claude/CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Read @AGENTS.md for more
1+
See @../AGENTS.md
22

AGENTS.md

Lines changed: 139 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,24 +213,98 @@ tracer/src/Datadog.Trace
213213

214214
## Coding Style & Naming Conventions
215215

216-
- C#: .editorconfig (4-space indent, System.* first, prefer var). Types/methods PascalCase; locals camelCase.
216+
- C#: see `.editorconfig` (4-space indent, `System.*` first, prefer `var`). Types/methods PascalCase; locals camelCase.
217217
- When a "using" directive is missing in a file, add it instead of using fully-qualified type names.
218218
- Use modern C# syntax, but avoid syntax that requires types not available in older runtimes (for example, don't use syntax that requires ValueTuple because is not included in .NET Framework 4.6.1)
219-
- StyleCop: `tracer/stylecop.json`; address warnings before pushing.
220-
- C/C++: `.clang-format`; keep consistent naming.
219+
- Prefer modern collection expressions (`[]`)
220+
- StyleCop: see `tracer/stylecop.json`; address warnings before pushing.
221+
- C/C++: see `.clang-format`; keep consistent naming.
222+
223+
## Logging Guidelines
224+
225+
Use clear, customer-facing terminology in log messages to avoid confusion. `Profiler` is ambiguous—it can refer to the .NET profiling APIs we use internally or the Continuous Profiler product.
226+
227+
**Customer-facing terminology (high-level logs):**
228+
- **Datadog SDK** — When disabling the entire product or referring to the whole monitoring solution
229+
- Example: `"The Datadog SDK has been disabled"`
230+
- **Instrumentation** or **Instrumentation component** — For the native tracer auto-instrumentation
231+
- Example: `"Instrumentation has been disabled"` or `"The Instrumentation component failed to initialize"`
232+
- **Continuous Profiler** — Always use full name for the profiling product
233+
- Example: `"The Continuous Profiler has been disabled"`
234+
- **Datadog.Trace.dll** — For the managed tracer assembly (avoid "managed profiler")
235+
- Example: `"Unable to initialize: Datadog.Trace.dll was not yet loaded into the App Domain"`
236+
237+
**Internal/technical naming (still valid):**
238+
- Native loader, Native tracer, Managed tracer loader, Managed tracer, Libdatadog, Continuous Profiler
239+
- `CorProfiler` / `ICorProfiler` / `COR Profiler` for runtime components
240+
241+
**Reference:** See PR 7467 for examples of consistent terminology in native logs.
242+
243+
## Performance Guidelines
244+
245+
- Minimize heap allocations: The tracer runs in-process with customer applications and must have minimal performance impact. Avoid unnecessary object allocations, prefer value types where appropriate, use object pooling for frequently allocated objects, and cache reusable instances.
246+
247+
### Performance-Critical Code Paths
248+
249+
Performance is especially critical in two areas:
250+
251+
1. **Bootstrap/Startup Code**: Initialization code runs at application startup in every instrumented process, including:
252+
- The managed loader (`Datadog.Trace.ClrProfiler.Managed.Loader`)
253+
- Tracer initialization in `Datadog.Trace` (static constructors, configuration loading, first tracer instance creation)
254+
- Integration registration and setup
255+
256+
Any allocations or inefficiencies here directly impact application startup time and customer experience. This code must be extremely efficient.
257+
258+
2. **Hot Paths**: Code that executes frequently during application runtime, such as:
259+
- Span creation and tagging (executes on every traced operation)
260+
- Context propagation (executes on every HTTP request/response)
261+
- Sampling decisions (executes on every trace)
262+
- Integration instrumentation callbacks (executes on every instrumented method call)
263+
- Any code in the request/response pipeline
264+
265+
In these areas, even small inefficiencies are multiplied by the frequency of execution and can significantly impact application performance.
266+
267+
### Performance Optimization Patterns
268+
269+
**Zero-Allocation Provider Structs**
270+
- Use `readonly struct` implementing interfaces instead of classes for frequently-instantiated abstractions
271+
- Use generic type parameters with interface constraints to avoid boxing: `<TProvider> where TProvider : IProvider`
272+
- Example: `EnvironmentVariableProvider` in managed loader (see tracer/src/Datadog.Trace.ClrProfiler.Managed.Loader)
273+
- Benefits: Zero heap allocations, no boxing, better JIT optimization
274+
275+
**Avoid Allocation in Logging**
276+
- Use format strings (`Log("value: {0}", x)`) instead of interpolation (`Log($"value: {x}")`)
277+
- Allows logger to check level before formatting
278+
- Critical in startup and hot paths where logging is frequent
279+
280+
**Avoid params Array Allocations**
281+
- Provide overloads for common cases (0, 1, 2 args) that avoid `params object?[]` array allocation
282+
- Keep params overload as fallback for 3+ args
283+
- Example: Logging methods with multiple overloads for different argument counts
221284

222285
## Testing Guidelines
223286

224287
- Frameworks: xUnit (managed), GoogleTest (native).
225288
- Projects: `*.Tests.csproj` under `tracer/test`, native under `profiler/test`.
226289
- Filters: `--filter "Category=Smoke"`, `--framework net6.0` as needed.
227290
- Docker: Many integration tests require Docker; services in `docker-compose.yml`.
291+
- Test style: Inline result variables in assertions. Prefer `SomeMethod().Should().Be(expected)` over storing intermediate `result` variables.
292+
293+
### Testing Patterns
294+
295+
**Abstraction for Testability**
296+
- Extract interfaces for environment/filesystem dependencies (e.g., `IEnvironmentVariableProvider`)
297+
- Allows mocking in unit tests without affecting production performance
298+
- Use struct implementations with generic constraints for zero-allocation production code
299+
- Example: Managed loader tests use `MockEnvironmentVariableProvider` for isolation (see tracer/test/Datadog.Trace.Tests/ClrProfiler/Managed/Loader/)
228300

229301
## Commit & Pull Request Guidelines
230302

231-
- Commits: Imperative; optional scope tag (e.g., `fix(telemetry): …` or `[Debugger] …`); reference issues.
303+
- Commits: Imperative; optional scope tag (e.g., `fix(telemetry): …` or `[Debugger] …`); reference issues. Keep messages concise - avoid including full diffs or extensive details in the commit message.
232304
- PRs: Clear description, linked issues, risks/rollout, screenshots/logs if behavior changes.
233-
- follow the existing PR description template in .github/pull_request_template.md
305+
- Follow the existing PR description template in `.github/pull_request_template.md`
306+
- Keep descriptions concise - provide essential context without excessive detail
307+
- Focus on "what" and "why", with brief "how" for complex changes
234308
- CI: All checks green; include tests/docs for changes.
235309

236310
## Internal Docs & References
@@ -282,7 +356,67 @@ tracer/src/Datadog.Trace
282356
- Build/registration: Definitions are discovered and generated during build; no manual native changes required.
283357
- Tests: Add tests under `tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests` and corresponding samples under `tracer/test/test-applications/integrations`. Run with OS‑specific Nuke targets; filter with `--filter`/`--framework`.
284358

359+
## Azure Functions
360+
361+
### Automatic Instrumentation Setup
362+
363+
**Windows (Premium / Elastic Premium / Dedicated / App Services hosting plans)**
364+
- Use the Azure App Services Site Extension, not the NuGet package.
365+
366+
**Other scenarios (e.g., Linux Consumption, Container Apps)**
367+
- Add NuGet package: `Datadog.AzureFunctions`
368+
- Configure environment variables:
369+
370+
**Windows environment variables:**
371+
```
372+
CORECLR_ENABLE_PROFILING=1
373+
CORECLR_PROFILER={846F5F1C-F9AE-4B07-969E-05C26BC060D8}
374+
CORECLR_PROFILER_PATH_64=C:\home\site\wwwroot\datadog\win-x64\Datadog.Trace.ClrProfiler.Native.dll
375+
CORECLR_PROFILER_PATH_32=C:\home\site\wwwroot\datadog\win-x86\Datadog.Trace.ClrProfiler.Native.dll
376+
DD_DOTNET_TRACER_HOME=C:\home\site\wwwroot\datadog
377+
DOTNET_STARTUP_HOOKS=C:\home\site\wwwroot\Datadog.Serverless.Compat.dll
378+
```
379+
380+
**Linux environment variables:**
381+
```
382+
CORECLR_ENABLE_PROFILING=1
383+
CORECLR_PROFILER={846F5F1C-F9AE-4B07-969E-05C26BC060D8}
384+
CORECLR_PROFILER_PATH=/home/site/wwwroot/datadog/linux-x64/Datadog.Trace.ClrProfiler.Native.so
385+
DD_DOTNET_TRACER_HOME=/home/site/wwwroot/datadog
386+
DOTNET_STARTUP_HOOKS=/home/site/wwwroot/Datadog.Serverless.Compat.dll
387+
```
388+
389+
### Development & Testing
390+
391+
- Integration details: See `docs/development/AzureFunctions.md` for in-process vs isolated worker model differences, instrumentation specifics, and ASP.NET Core integration.
392+
- Tests: `BuildAndRunWindowsAzureFunctionsTests` Nuke target; samples under `tracer/test/test-applications/azure-functions/`.
393+
- Dependencies: `Datadog.AzureFunctions` transitively references `Datadog.Serverless.Compat` ([datadog-serverless-compat-dotnet](https://github.com/DataDog/datadog-serverless-compat-dotnet)), which contains the Datadog Agent executable. The agent process is started either via `DOTNET_STARTUP_HOOKS` or by calling `Datadog.Serverless.CompatibilityLayer.Start()` explicitly during bootstrap in user code.
394+
285395
## Security & Configuration Tips
286396

287397
- Do not commit secrets; prefer env vars (`DD_*`). `.env` should not contain credentials.
288398
- Use `global.json` SDK; confirm with `dotnet --version`.
399+
400+
## Glossary
401+
402+
Common acronyms used in this repository:
403+
404+
- **AAS** — Azure App Services
405+
- **AAP** — App and API Protection (formerly ASM, previously AppSec)
406+
- **AOT** — Ahead-of-Time (compilation)
407+
- **APM** — Application Performance Monitoring
408+
- **ASM** — Application Security Management (formerly AppSec; now AAP)
409+
- **CI** — Continuous Integration / CI Visibility
410+
- **CP** — Continuous Profiler
411+
- **DBM** — Database Monitoring
412+
- **DI** — Dynamic Instrumentation
413+
- **DSM** — Data Streams Monitoring
414+
- **IAST** — Interactive Application Security Testing
415+
- **JIT** — Just-in-Time (compiler)
416+
- **OTEL** — OpenTelemetry
417+
- **R2R** — ReadyToRun
418+
- **RASP** — Runtime Application Self-Protection
419+
- **RCM** — Remote Configuration Management
420+
- **RID** — Runtime Identifier
421+
- **TFM** — Target Framework Moniker
422+
- **WAF** — Web Application Firewall

0 commit comments

Comments
 (0)