@cratis/pi 7.102.0 → 7.103.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package/corpus/harnesses/copilot/instructions/profiles.instructions.md +10 -1
- package/package/corpus/harnesses/copilot/instructions/pull-requests.instructions.md +2 -0
- package/package/corpus/harnesses/copilot/instructions/secrets.instructions.md +4 -0
- package/package/corpus/hooks/README.md +11 -1
- package/package/corpus/hooks/scripts/cratis-check-pr.mjs +12 -1
- package/package/corpus/hooks/scripts/cratis-guard-secrets.sh +79 -23
- package/package/corpus/hooks/scripts/cratis-guard-writes.sh +145 -40
- package/package/corpus/rules/profiles.md +10 -1
- package/package/corpus/rules/pull-requests.md +2 -0
- package/package/corpus/rules/secrets.md +4 -0
- package/package/corpus/skills/analyzing-dotnet-performance/LICENSE +23 -0
- package/package/corpus/skills/analyzing-dotnet-performance/NOTICE +36 -0
- package/package/corpus/skills/analyzing-dotnet-performance/SKILL.md +214 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/async-patterns.md +122 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/collections-and-linq.md +220 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/critical-patterns.md +291 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/io-and-serialization.md +135 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/memory-and-strings.md +219 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/regex-patterns.md +95 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/structural-patterns.md +38 -0
- package/package/corpus/skills/binlog-generation/LICENSE +23 -0
- package/package/corpus/skills/binlog-generation/NOTICE +22 -0
- package/package/corpus/skills/binlog-generation/SKILL.md +129 -0
- package/package/corpus/skills/check-bin-obj-clash/LICENSE +23 -0
- package/package/corpus/skills/check-bin-obj-clash/NOTICE +27 -0
- package/package/corpus/skills/check-bin-obj-clash/SKILL.md +127 -0
- package/package/corpus/skills/check-bin-obj-clash/references/common-causes-and-fixes.md +206 -0
- package/package/corpus/skills/coverage-analysis/LICENSE +23 -0
- package/package/corpus/skills/coverage-analysis/NOTICE +32 -0
- package/package/corpus/skills/coverage-analysis/SKILL.md +198 -0
- package/package/corpus/skills/coverage-analysis/references/guidelines.md +68 -0
- package/package/corpus/skills/coverage-analysis/references/output-format.md +91 -0
- package/package/corpus/skills/coverage-analysis/references/report-generation.md +58 -0
- package/package/corpus/skills/coverage-analysis/references/setup-discovery.md +307 -0
- package/package/corpus/skills/coverage-analysis/scripts/Compute-CrapScores.ps1 +80 -0
- package/package/corpus/skills/coverage-analysis/scripts/CoverageData.ps1 +272 -0
- package/package/corpus/skills/coverage-analysis/scripts/Extract-MethodCoverage.ps1 +65 -0
- package/package/corpus/skills/csharp-refactoring/LICENSE +23 -0
- package/package/corpus/skills/csharp-refactoring/NOTICE +22 -0
- package/package/corpus/skills/csharp-refactoring/SKILL.md +175 -0
- package/package/corpus/skills/csharp-refactoring/references/operation-catalog.md +37 -0
- package/package/corpus/skills/directory-build-organization/LICENSE +23 -0
- package/package/corpus/skills/directory-build-organization/NOTICE +21 -0
- package/package/corpus/skills/directory-build-organization/SKILL.md +205 -0
- package/package/corpus/skills/directory-build-organization/references/common-patterns.md +56 -0
- package/package/corpus/skills/directory-build-organization/references/multi-level-examples.md +167 -0
- package/package/corpus/skills/directory-build-organization/references/targetframework-props-pitfall.md +54 -0
- package/package/corpus/skills/dotnet-aot-compat/LICENSE +23 -0
- package/package/corpus/skills/dotnet-aot-compat/NOTICE +18 -0
- package/package/corpus/skills/dotnet-aot-compat/SKILL.md +265 -0
- package/package/corpus/skills/dotnet-aot-compat/references/polyfills.md +43 -0
- package/package/corpus/skills/dotnet-trace-collect/LICENSE +23 -0
- package/package/corpus/skills/dotnet-trace-collect/NOTICE +65 -0
- package/package/corpus/skills/dotnet-trace-collect/SKILL.md +116 -0
- package/package/corpus/skills/dotnet-trace-collect/references/dotnet-monitor.md +97 -0
- package/package/corpus/skills/dotnet-trace-collect/references/dotnet-trace-collect-linux.md +84 -0
- package/package/corpus/skills/dotnet-trace-collect/references/dotnet-trace-collect.md +91 -0
- package/package/corpus/skills/dotnet-trace-collect/references/perfcollect.md +200 -0
- package/package/corpus/skills/dotnet-trace-collect/references/perfview.md +141 -0
- package/package/corpus/skills/dotnet-trace-collect/references/tool-selection.md +160 -0
- package/package/corpus/skills/dump-collect/LICENSE +23 -0
- package/package/corpus/skills/dump-collect/NOTICE +40 -0
- package/package/corpus/skills/dump-collect/SKILL.md +97 -0
- package/package/corpus/skills/dump-collect/references/container-dumps.md +412 -0
- package/package/corpus/skills/dump-collect/references/coreclr-dumps.md +108 -0
- package/package/corpus/skills/dump-collect/references/nativeaot-dumps.md +280 -0
- package/package/corpus/skills/eliminate-redundant-restores/LICENSE +23 -0
- package/package/corpus/skills/eliminate-redundant-restores/NOTICE +19 -0
- package/package/corpus/skills/eliminate-redundant-restores/SKILL.md +112 -0
- package/package/corpus/skills/extension-points/LICENSE +23 -0
- package/package/corpus/skills/extension-points/NOTICE +18 -0
- package/package/corpus/skills/extension-points/SKILL.md +248 -0
- package/package/corpus/skills/filter-syntax/LICENSE +23 -0
- package/package/corpus/skills/filter-syntax/NOTICE +17 -0
- package/package/corpus/skills/filter-syntax/SKILL.md +179 -0
- package/package/corpus/skills/including-generated-files/LICENSE +23 -0
- package/package/corpus/skills/including-generated-files/NOTICE +17 -0
- package/package/corpus/skills/including-generated-files/SKILL.md +139 -0
- package/package/corpus/skills/microbenchmarking/LICENSE +23 -0
- package/package/corpus/skills/microbenchmarking/NOTICE +36 -0
- package/package/corpus/skills/microbenchmarking/SKILL.md +131 -0
- package/package/corpus/skills/microbenchmarking/references/bdn-internals-and-tuning.md +143 -0
- package/package/corpus/skills/microbenchmarking/references/comparison-strategies.md +200 -0
- package/package/corpus/skills/microbenchmarking/references/diagnosers-and-exporters.md +150 -0
- package/package/corpus/skills/microbenchmarking/references/project-setup-and-running.md +189 -0
- package/package/corpus/skills/microbenchmarking/references/writing-benchmarks.md +310 -0
- package/package/corpus/skills/msbuild/LICENSE +23 -0
- package/package/corpus/skills/msbuild/NOTICE +55 -0
- package/package/corpus/skills/msbuild/SKILL.md +117 -0
- package/package/corpus/skills/msbuild/references/antipatterns/additional-antipatterns.md +291 -0
- package/package/corpus/skills/msbuild/references/antipatterns/incremental-build-inputs-outputs.md +57 -0
- package/package/corpus/skills/msbuild/references/antipatterns/private-assets.md +29 -0
- package/package/corpus/skills/msbuild/references/binlog-failure-analysis.md +85 -0
- package/package/corpus/skills/msbuild/references/binlog-generation.md +69 -0
- package/package/corpus/skills/msbuild/references/build-perf-baseline.md +493 -0
- package/package/corpus/skills/msbuild/references/build-perf-diagnostics.md +268 -0
- package/package/corpus/skills/msbuild/references/copy-to-output-directory.md +183 -0
- package/package/corpus/skills/msbuild/references/eval-performance.md +190 -0
- package/package/corpus/skills/msbuild/references/extension-points.md +281 -0
- package/package/corpus/skills/msbuild/references/incremental-build.md +365 -0
- package/package/corpus/skills/msbuild/references/msbuild-antipatterns.md +401 -0
- package/package/corpus/skills/orleans/LICENSE +21 -0
- package/package/corpus/skills/orleans/NOTICE +64 -0
- package/package/corpus/skills/orleans/SKILL.md +140 -0
- package/package/corpus/skills/orleans/references/anti-patterns.md +660 -0
- package/package/corpus/skills/orleans/references/configuration-api.md +933 -0
- package/package/corpus/skills/orleans/references/examples.md +66 -0
- package/package/corpus/skills/orleans/references/grain-api.md +784 -0
- package/package/corpus/skills/orleans/references/grains.md +75 -0
- package/package/corpus/skills/orleans/references/hosting.md +71 -0
- package/package/corpus/skills/orleans/references/implementation.md +591 -0
- package/package/corpus/skills/orleans/references/official-docs-index.md +250 -0
- package/package/corpus/skills/orleans/references/patterns.md +811 -0
- package/package/corpus/skills/orleans/references/persistence-api.md +495 -0
- package/package/corpus/skills/orleans/references/primitive-selection.md +35 -0
- package/package/corpus/skills/orleans/references/scheduling-and-services.md +295 -0
- package/package/corpus/skills/orleans/references/serialization-api.md +299 -0
- package/package/corpus/skills/orleans/references/streaming-api.md +396 -0
- package/package/corpus/skills/orleans/references/testing-patterns.md +210 -0
- package/package/corpus/skills/platform-detection/LICENSE +23 -0
- package/package/corpus/skills/platform-detection/NOTICE +17 -0
- package/package/corpus/skills/platform-detection/SKILL.md +230 -0
- package/package/corpus/skills/platform-detection/references/command-mode.md +27 -0
- package/package/corpus/skills/profiling/LICENSE +21 -0
- package/package/corpus/skills/profiling/NOTICE +50 -0
- package/package/corpus/skills/profiling/SKILL.md +144 -0
- package/package/corpus/skills/profiling/references/commands.md +439 -0
- package/package/corpus/skills/profiling/references/patterns.md +586 -0
- package/package/corpus/skills/profiling/references/profiling.md +190 -0
- package/package/corpus/skills/run-tests/LICENSE +23 -0
- package/package/corpus/skills/run-tests/NOTICE +19 -0
- package/package/corpus/skills/run-tests/SKILL.md +305 -0
- package/package/corpus/skills/target-authoring/LICENSE +23 -0
- package/package/corpus/skills/target-authoring/NOTICE +17 -0
- package/package/corpus/skills/target-authoring/SKILL.md +165 -0
- package/package/corpus/skills/vectorization/LICENSE +23 -0
- package/package/corpus/skills/vectorization/NOTICE +17 -0
- package/package/corpus/skills/vectorization/SKILL.md +189 -0
- package/package/profile-catalog.json +85 -1
- package/package.json +1 -1
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dotnet-aot-compat
|
|
3
|
+
description: 'Makes .NET projects compatible with Native AOT and trimming by resolving IL trim and AOT analyzer warnings. Use when making a project AOT-compatible, fixing trimming warnings, resolving IL2026, IL2067, IL2070, IL2072, or IL3050, adding DynamicallyAccessedMembers annotations, or enabling IsAotCompatible. Not for publishing native AOT binaries, optimizing binary size, replacing reflection-heavy libraries, or .NET Framework projects.'
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!-- Modified by Cratis from dotnet's original (MIT): frontmatter, applicability, navigation and the changes listed in NOTICE. Upstream: https://github.com/dotnet/skills (plugins/dotnet-upgrade/skills/dotnet-aot-compat/SKILL.md; see NOTICE) -->
|
|
8
|
+
|
|
9
|
+
# dotnet-aot-compat
|
|
10
|
+
|
|
11
|
+
Cratis rules in `.cratis/ai/rules/` (including `csharp.md`, `specs.csharp.md`, and `orleans.md`) and the `cratis-*` skills win where they differ. Arc host trimming/NativeAOT setup belongs to **cratis-arc-hosting**.
|
|
12
|
+
|
|
13
|
+
Make .NET projects compatible with Native AOT and trimming by systematically resolving all IL trim/AOT analyzer warnings.
|
|
14
|
+
|
|
15
|
+
## When to Use This Skill
|
|
16
|
+
|
|
17
|
+
- **"Make this project AOT-compatible"**
|
|
18
|
+
- **"Fix trimming warnings"** or **"fix IL warnings"**
|
|
19
|
+
- **"Resolve IL2070 / IL2067 / IL2072 / IL2026 / IL3050 warnings"**
|
|
20
|
+
- **"Add DynamicallyAccessedMembers annotations"**
|
|
21
|
+
- **"Enable IsAotCompatible in my .csproj"**
|
|
22
|
+
- **"My project has trim analyzer warnings after upgrading to net8.0"**
|
|
23
|
+
- **"Annotate reflection code for the trimmer"**
|
|
24
|
+
|
|
25
|
+
## When Not to Use This Skill
|
|
26
|
+
|
|
27
|
+
Do not use this skill when the project exclusively targets .NET Framework (net4x), which does not support the trim/AOT analyzers.
|
|
28
|
+
|
|
29
|
+
## Prerequisites
|
|
30
|
+
|
|
31
|
+
An existing .NET project targeting net8.0 or later (or multi-targeting with at least one net8.0+ TFM) and the corresponding .NET SDK installed.
|
|
32
|
+
|
|
33
|
+
## Background: What AOT Compatibility Means
|
|
34
|
+
|
|
35
|
+
Native AOT and the IL trimmer perform static analysis to determine what code is reachable. Reflection can break this analysis because the trimmer can't see what types/members are accessed at runtime. The `IsAotCompatible` property enables analyzers that flag these issues as build warnings (ILXXXX codes).
|
|
36
|
+
|
|
37
|
+
## Critical Rules
|
|
38
|
+
|
|
39
|
+
### ❌ Never suppress warnings incorrectly
|
|
40
|
+
|
|
41
|
+
- **NEVER** use `#pragma warning disable` for IL warnings. It hides warnings from the Roslyn analyzer at build time, but the IL linker and AOT compiler still see the issue. The code will fail at trim/publish time.
|
|
42
|
+
- **NEVER** use `[UnconditionalSuppressMessage]`. It tells both the analyzer AND the linker to ignore the warning, meaning the trimmer cannot verify safety. Raising an error at build time is always preferable to hiding the issue and having it silently break at runtime.
|
|
43
|
+
|
|
44
|
+
### 💡 Preferred approaches
|
|
45
|
+
|
|
46
|
+
- **Prefer** `[DynamicallyAccessedMembers]` annotations to flow type information through the call chain.
|
|
47
|
+
- **Prefer** refactoring to eliminate patterns that break annotation flow (e.g., boxing `Type` through `object[]`).
|
|
48
|
+
- **Use** `[RequiresUnreferencedCode]` / `[RequiresDynamicCode]` / `[RequiresAssemblyFiles]` to mark methods as fundamentally incompatible with trimming, propagating the requirement to callers. This surfaces the issue clearly rather than hiding it — callers must explicitly acknowledge the incompatibility.
|
|
49
|
+
|
|
50
|
+
### Annotation flow is key
|
|
51
|
+
|
|
52
|
+
The trimmer tracks `[DynamicallyAccessedMembers]` annotations through assignments, parameter passing, and return values. If this flow is broken (e.g., by boxing a `Type` into `object`, storing in an untyped collection, or casting through interfaces), the trimmer loses track and warns. The fix is to preserve the flow, not suppress the warning.
|
|
53
|
+
|
|
54
|
+
## Step-by-Step Procedure
|
|
55
|
+
|
|
56
|
+
> **Do not explore the codebase up-front.** The build warnings tell you exactly which files and lines need changes. Follow a tight loop: **build → pick a warning → open that file at that line → apply the fix recipe → rebuild**. Reading or analyzing source files beyond what a specific warning points you to is wasted effort and leads to timeouts. Let the compiler guide you.
|
|
57
|
+
>
|
|
58
|
+
> ❌ Do NOT run `find`, `ls`, or `grep` to understand the project structure before building. Do NOT read README, docs, or architecture files. Your first action should be Step 1 (enable AOT analysis), then build.
|
|
59
|
+
|
|
60
|
+
### Step 1: Enable AOT analysis in the .csproj
|
|
61
|
+
|
|
62
|
+
Add `IsAotCompatible`. If the project doesn't exclusively target net8.0+, add a TFM condition (AOT analysis requires net8.0+):
|
|
63
|
+
|
|
64
|
+
```xml
|
|
65
|
+
<PropertyGroup>
|
|
66
|
+
<IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">true</IsAotCompatible>
|
|
67
|
+
</PropertyGroup>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
This automatically sets `EnableTrimAnalyzer=true` and `EnableAotAnalyzer=true` for compatible TFMs. For multi-targeting projects (e.g., `netstandard2.0;net8.0`), the condition ensures no `NETSDK1210` warnings on older TFMs.
|
|
71
|
+
|
|
72
|
+
### Step 2: Build and collect warnings
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
dotnet build <project.csproj> -f <net8.0-or-later-tfm> --no-incremental 2>&1 | grep 'IL[0-9]\{4\}'
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Sort and deduplicate. Common warning codes:
|
|
79
|
+
- **IL2070**: Reflection call on a `Type` parameter missing `[DynamicallyAccessedMembers]`
|
|
80
|
+
- **IL2067**: Passing an unannotated `Type` to a method expecting `[DynamicallyAccessedMembers]`
|
|
81
|
+
- **IL2072**: Return value or extracted value missing annotation (often from unboxing)
|
|
82
|
+
- **IL2057**: `Type.GetType(string)` with a non-constant argument
|
|
83
|
+
- **IL2026**: Calling a method marked `[RequiresUnreferencedCode]`
|
|
84
|
+
- **IL2050**: P/invoke method with COM marshalling parameters
|
|
85
|
+
- **IL2075**: Return value flows into reflection without annotation
|
|
86
|
+
- **IL2091**: Generic argument missing `[DynamicallyAccessedMembers]` required by constraint
|
|
87
|
+
- **IL3000**: `Assembly.Location` returns empty string in single-file/AOT apps
|
|
88
|
+
- **IL3050**: Calling a method marked `[RequiresDynamicCode]`
|
|
89
|
+
|
|
90
|
+
### Step 3: Triage warnings by code (do NOT read every file)
|
|
91
|
+
|
|
92
|
+
Group the warnings from Step 2 by warning code and count them. **Do not open individual files yet.** Identify the top 1-2 patterns by count — these drive your fix strategy:
|
|
93
|
+
|
|
94
|
+
| Pattern | Typical fix |
|
|
95
|
+
|---------|-------------|
|
|
96
|
+
| Many IL2026 + IL3050 from `JsonSerializer` | **Go to Strategy C immediately** — create a `JsonSerializerContext`, then batch-update all call sites |
|
|
97
|
+
| IL2070/IL2087 on `Type` parameters | Add `[DynamicallyAccessedMembers]` to the innermost method, then cascade outward |
|
|
98
|
+
| IL2067 passing unannotated `Type` | Annotate the parameter at the source |
|
|
99
|
+
|
|
100
|
+
**In most real projects, IL2026/IL3050 from JsonSerializer dominate.** Start with Strategy C unless the warning breakdown clearly shows otherwise. After the batch JSON fix, handle remaining warnings with Strategies A–B. Only use Strategy D as a last resort.
|
|
101
|
+
|
|
102
|
+
### Step 4: Fix warnings iteratively (innermost first)
|
|
103
|
+
|
|
104
|
+
Work from the **innermost** reflection call outward. Each fix may cascade new warnings to callers.
|
|
105
|
+
|
|
106
|
+
**Stay warning-driven.** For each warning, open only the file and line the compiler reported, identify the pattern, apply the matching fix recipe below, and move on. Do not scan the codebase for similar patterns or try to understand the full architecture — fix what the compiler tells you, rebuild, and let new warnings guide the next change. Fix a small batch of warnings (5-10), then rebuild immediately to check progress.
|
|
107
|
+
|
|
108
|
+
**Use sub-agents when available.** If you can launch sub-agents (e.g., via a `task` tool), dispatch **multiple sub-agents in parallel** to edit different files simultaneously. Keep the main loop focused on building, parsing warnings, and dispatching — delegate actual file edits to sub-agents. For batch JSON updates, give each sub-agent 5-10 files to update in one prompt. **After 2 build-fix cycles, dispatch all remaining file edits to sub-agents in parallel — do not continue fixing files sequentially.** Example:
|
|
109
|
+
|
|
110
|
+
> Update these files to use source-generated JSON: `src/Models/Resource.Serialization.cs`, `src/Models/Identity.Serialization.cs`, `src/Models/Plan.Serialization.cs`. In each file, replace `JsonSerializer.Serialize(writer, value)` with `JsonSerializer.Serialize(writer, value, MyProjectJsonContext.Default.TypeName)` and `JsonSerializer.Deserialize<T>(ref reader)` with `JsonSerializer.Deserialize(ref reader, MyProjectJsonContext.Default.TypeName)`. Only edit the JsonSerializer call sites.
|
|
111
|
+
|
|
112
|
+
#### Strategy A: Add `[DynamicallyAccessedMembers]` (preferred)
|
|
113
|
+
|
|
114
|
+
When a method uses reflection on a `Type` parameter, annotate the parameter to tell the trimmer what members are needed:
|
|
115
|
+
|
|
116
|
+
```csharp
|
|
117
|
+
using System.Diagnostics.CodeAnalysis;
|
|
118
|
+
|
|
119
|
+
// Before (warns IL2070):
|
|
120
|
+
void Process(Type t) {
|
|
121
|
+
var method = t.GetMethod("Foo"); // trimmer can't verify
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// After (clean):
|
|
125
|
+
void Process([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t) {
|
|
126
|
+
var method = t.GetMethod("Foo"); // trimmer preserves public methods
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
When you annotate a parameter, **all callers** must now pass properly annotated types. This cascades outward — follow each caller and annotate or refactor as needed. **The caller's annotation must include at least the same member types as the callee's.** If the callee requires `PublicConstructors | NonPublicConstructors`, the caller must specify the same or a superset — using only `NonPublicConstructors` will produce IL2091.
|
|
131
|
+
|
|
132
|
+
#### Strategy B: Refactor to preserve annotation flow
|
|
133
|
+
|
|
134
|
+
When annotation flow is broken by boxing (storing `Type` in `object`, `object[]`, or untyped collections), **refactor** to pass the `Type` directly:
|
|
135
|
+
|
|
136
|
+
```csharp
|
|
137
|
+
// BROKEN: Type boxed into object[], annotation lost
|
|
138
|
+
void Process(object[] args) {
|
|
139
|
+
Type t = (Type)args[0]; // IL2072: annotation lost through boxing
|
|
140
|
+
Evaluate(t, ...);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// FIXED: Pass Type as a separate, annotated parameter
|
|
144
|
+
void Process(
|
|
145
|
+
object[] args,
|
|
146
|
+
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type calleeType,
|
|
147
|
+
...) {
|
|
148
|
+
Evaluate(calleeType, ...); // annotation flows cleanly
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Common patterns that break flow and how to fix them:
|
|
153
|
+
- **`object[]` parameter bags**: Extract the `Type` into a dedicated annotated parameter
|
|
154
|
+
- **Dictionary/List storage**: Use a typed field with annotation instead
|
|
155
|
+
- **Interface indirection**: Add annotation to the interface method's parameter
|
|
156
|
+
- **Property with boxing getter**: Annotate the property's return type
|
|
157
|
+
|
|
158
|
+
#### Strategy C: Source-generated JSON serialization (batch fix)
|
|
159
|
+
|
|
160
|
+
When most warnings are IL2026/IL3050 from `JsonSerializer.Serialize`/`Deserialize`, this is a single mechanical fix applied in bulk:
|
|
161
|
+
|
|
162
|
+
1. **Collect affected types** — grep for all `JsonSerializer.Serialize` and `JsonSerializer.Deserialize` call sites. Extract the type being serialized (the `<T>` in `Deserialize<T>`, or the runtime type of the object in `Serialize`).
|
|
163
|
+
|
|
164
|
+
2. **Create one `JsonSerializerContext`** with `[JsonSerializable]` for every type found. **Skip types from external packages** (e.g., `ResponseError` from `Azure.Core`) — they won't source-generate for types you don't own. Handle external types separately via Gotcha #1 below.
|
|
165
|
+
|
|
166
|
+
```csharp
|
|
167
|
+
[JsonSerializable(typeof(ManagedServiceIdentity))]
|
|
168
|
+
[JsonSerializable(typeof(SystemData))]
|
|
169
|
+
// ... one attribute per type YOU OWN
|
|
170
|
+
// Do NOT add types from external packages (e.g., ResponseError)
|
|
171
|
+
internal partial class MyProjectJsonContext : JsonSerializerContext { }
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
3. **Batch-update all call sites** — do not read each file individually. Apply the pattern mechanically:
|
|
175
|
+
- `JsonSerializer.Serialize(obj)` → `JsonSerializer.Serialize(obj, MyProjectJsonContext.Default.TypeName)`
|
|
176
|
+
- `JsonSerializer.Deserialize<T>(json)` → `JsonSerializer.Deserialize(json, MyProjectJsonContext.Default.TypeName)`
|
|
177
|
+
|
|
178
|
+
Find and update all call sites in one pass:
|
|
179
|
+
```bash
|
|
180
|
+
# Find all files with JsonSerializer calls
|
|
181
|
+
grep -rl 'JsonSerializer\.\(Serialize\|Deserialize\)' src/ --include='*.cs'
|
|
182
|
+
```
|
|
183
|
+
Then use sequential `edit` calls to apply the same transformation to every matching file. **Do not use `sed` for C# code** — generics like `Deserialize<T>()` have angle brackets and nested parentheses that sed will mangle.
|
|
184
|
+
|
|
185
|
+
4. **Build once** to verify. Remaining warnings will be non-serialization issues — handle those with Strategies A–B or D.
|
|
186
|
+
|
|
187
|
+
#### Strategy D: `[RequiresUnreferencedCode]` (last resort)
|
|
188
|
+
|
|
189
|
+
When a method fundamentally requires arbitrary reflection that cannot be statically described:
|
|
190
|
+
|
|
191
|
+
```csharp
|
|
192
|
+
[RequiresUnreferencedCode("Loads plugins by name using Assembly.Load")]
|
|
193
|
+
public void LoadPlugin(string assemblyName) {
|
|
194
|
+
var asm = Assembly.Load(assemblyName);
|
|
195
|
+
// ...
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
This propagates to callers — they must also be annotated with `[RequiresUnreferencedCode]`. Use sparingly; it marks the entire call chain as trim-incompatible.
|
|
200
|
+
|
|
201
|
+
### Step 5: Rebuild and repeat
|
|
202
|
+
|
|
203
|
+
After each small batch of fixes (5-10 warnings), rebuild with `--no-incremental` and check for new warnings. **Do not attempt to fix all warnings before rebuilding** — frequent rebuilds catch mistakes early and reveal cascading warnings. Fixes cascade — annotating an inner method may surface warnings in its callers. Repeat until `0 Warning(s)`.
|
|
204
|
+
|
|
205
|
+
### Step 6: Validate all TFMs
|
|
206
|
+
|
|
207
|
+
Build all target frameworks to ensure:
|
|
208
|
+
- **0 IL warnings** on net8.0+ TFMs
|
|
209
|
+
- **No NETSDK1210 warnings** (the `IsAotCompatible` condition handles this)
|
|
210
|
+
- **Clean builds** on older TFMs (netstandard2.0, net472, etc.)
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
dotnet build <project.csproj> # builds all TFMs
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Stop Signals
|
|
217
|
+
|
|
218
|
+
- **Do not analyze more than 2-3 representative files per warning pattern.** After identifying the fix for a pattern, apply it to all matching files without reading each one first.
|
|
219
|
+
- **Start fixing after one build.** Do not do a second analysis pass — begin implementing fixes for the most common warning pattern immediately after Step 3 triage.
|
|
220
|
+
- Stop after achieving **0 IL warnings** for net8.0+ TFMs. Don't optimize or refactor already-clean annotations.
|
|
221
|
+
- If a warning requires **architectural refactoring** beyond annotation flow fixes (e.g., replacing an entire serialization layer), document it and stop — don't rewrite large subsystems.
|
|
222
|
+
- Limit to **3 build-fix iterations** per warning. If annotation flow doesn't resolve it after 3 attempts, escalate to `[RequiresUnreferencedCode]`.
|
|
223
|
+
- Don't chase warnings in **third-party dependencies** you can't modify. Note them and move on.
|
|
224
|
+
- If the user asked a scoped question (e.g., "fix warnings in this file"), don't expand to the entire project.
|
|
225
|
+
|
|
226
|
+
## Polyfills for Older TFMs
|
|
227
|
+
|
|
228
|
+
For multi-targeting projects that include netstandard2.0 or net472, you need polyfills for `DynamicallyAccessedMembersAttribute` and related types. See [references/polyfills.md](references/polyfills.md).
|
|
229
|
+
|
|
230
|
+
## Common Gotchas
|
|
231
|
+
|
|
232
|
+
1. **External types without AOT-safe serialization**: When a type comes from a dependency you can't modify (e.g., `ResponseError` from `Azure.Core`) and it lacks a source-generated serializer, `Options.GetConverter<T>()` is reflection-based and will produce IL warnings. First check if the type implements `IJsonModel<T>` (common in Azure SDK) — if so, bypass `JsonSerializer` entirely:
|
|
233
|
+
|
|
234
|
+
```csharp
|
|
235
|
+
// Before (IL2026 — JsonSerializer uses reflection):
|
|
236
|
+
JsonSerializer.Serialize(writer, errorValue);
|
|
237
|
+
|
|
238
|
+
// After (AOT-safe — uses IJsonModel directly):
|
|
239
|
+
((IJsonModel<ResponseError>)errorValue).Write(writer, ModelReaderWriterOptions.Json);
|
|
240
|
+
|
|
241
|
+
// For deserialization:
|
|
242
|
+
var error = ((IJsonModel<ResponseError>)new ResponseError()).Create(ref reader, ModelReaderWriterOptions.Json);
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Do **not** add the external type to your `JsonSerializerContext` — it won't source-generate for types you don't own. If the type doesn't implement `IJsonModel<T>`, write a custom `JsonConverter<T>` with manual `Utf8JsonReader`/`Utf8JsonWriter` logic and register it via `[JsonSourceGenerationOptions]` on your context.
|
|
246
|
+
|
|
247
|
+
2. **Serialization libraries**: Most reflection-based serializers (e.g., `Newtonsoft.Json`, `XmlSerializer`) are not AOT-compatible. Migrate to a source-generation-based serializer such as `System.Text.Json` with a `JsonSerializerContext`. If migration is not feasible, mark the serialization call site with `[RequiresUnreferencedCode]`.
|
|
248
|
+
|
|
249
|
+
3. **Shared projects / projitems**: When source is shared between multiple projects via `<Import>`, annotations added to shared code affect ALL consuming projects. Verify that all consumers still build cleanly.
|
|
250
|
+
|
|
251
|
+
## References
|
|
252
|
+
|
|
253
|
+
[Limitations](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#limitations-of-native-aot-deployment)
|
|
254
|
+
[Conceptual: Understanding trimming](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-concepts)
|
|
255
|
+
[How-to: trim compat](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/fixing-warnings)
|
|
256
|
+
|
|
257
|
+
## Checklist
|
|
258
|
+
|
|
259
|
+
- [ ] Added `<IsAotCompatible>` with TFM condition to .csproj
|
|
260
|
+
- [ ] Built with AOT analyzers enabled (net8.0+ TFM)
|
|
261
|
+
- [ ] Fixed all IL warnings via annotations or refactoring
|
|
262
|
+
- [ ] No `#pragma warning disable` or `[UnconditionalSuppressMessage]` used for any IL warning
|
|
263
|
+
- [ ] Polyfills present for older TFMs if needed
|
|
264
|
+
- [ ] All target frameworks build with 0 warnings
|
|
265
|
+
- [ ] Verified shared/linked source doesn't break sibling projects
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Polyfills for Older TFMs
|
|
2
|
+
|
|
3
|
+
`DynamicallyAccessedMembersAttribute` shipped in .NET 5. For projects targeting netstandard2.0 or net472, you need a polyfill. The trimmer recognizes the attribute by name, so a local copy works:
|
|
4
|
+
|
|
5
|
+
```csharp
|
|
6
|
+
#if !NET
|
|
7
|
+
namespace System.Diagnostics.CodeAnalysis
|
|
8
|
+
{
|
|
9
|
+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.ReturnValue |
|
|
10
|
+
AttributeTargets.GenericParameter | AttributeTargets.Parameter |
|
|
11
|
+
AttributeTargets.Property, Inherited = false)]
|
|
12
|
+
internal sealed class DynamicallyAccessedMembersAttribute : Attribute
|
|
13
|
+
{
|
|
14
|
+
public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes)
|
|
15
|
+
=> MemberTypes = memberTypes;
|
|
16
|
+
public DynamicallyAccessedMemberTypes MemberTypes { get; }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
[Flags]
|
|
20
|
+
internal enum DynamicallyAccessedMemberTypes
|
|
21
|
+
{
|
|
22
|
+
None = 0,
|
|
23
|
+
PublicParameterlessConstructor = 0x0001,
|
|
24
|
+
PublicConstructors = 0x0002 | PublicParameterlessConstructor,
|
|
25
|
+
NonPublicConstructors = 0x0004,
|
|
26
|
+
PublicMethods = 0x0008,
|
|
27
|
+
NonPublicMethods = 0x0010,
|
|
28
|
+
PublicFields = 0x0020,
|
|
29
|
+
NonPublicFields = 0x0040,
|
|
30
|
+
PublicNestedTypes = 0x0080,
|
|
31
|
+
NonPublicNestedTypes = 0x0100,
|
|
32
|
+
PublicProperties = 0x0200,
|
|
33
|
+
NonPublicProperties = 0x0400,
|
|
34
|
+
PublicEvents = 0x0800,
|
|
35
|
+
NonPublicEvents = 0x1000,
|
|
36
|
+
Interfaces = 0x2000,
|
|
37
|
+
All = ~None // Discouraged — prefer specific flags
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
#endif
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Similarly for `RequiresUnreferencedCodeAttribute` and `UnconditionalSuppressMessageAttribute` if needed on older TFMs.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) .NET Foundation and Contributors
|
|
4
|
+
|
|
5
|
+
All rights reserved.
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
.NET Trace Collect
|
|
2
|
+
Copyright (c) .NET Foundation and Contributors
|
|
3
|
+
Licensed under the MIT License. See LICENSE.
|
|
4
|
+
|
|
5
|
+
Upstream source: https://github.com/dotnet/skills/blob/a6bf43ab61967c30919334986515163ab24d7635/plugins/dotnet-diag/skills/dotnet-trace-collect/SKILL.md
|
|
6
|
+
|
|
7
|
+
Changes made by Cratis:
|
|
8
|
+
|
|
9
|
+
LICENSE:
|
|
10
|
+
- Copy upstream MIT license and copyright verbatim.
|
|
11
|
+
|
|
12
|
+
SKILL.md:
|
|
13
|
+
- Normalize frontmatter serialization, add MIT license where absent; preserve name and description.
|
|
14
|
+
- Add marked modification/source comment and applicability/Cratis precedence line.
|
|
15
|
+
- Prefix official tool downloads/installs with marked approval/pinned-version guidance and privileged/perfcollect examples with explicit root/container-security approval, where present.
|
|
16
|
+
- Move the complete ### Step 2: Recommend diagnostic tools section verbatim into references/tool-selection.md to fit the body limit; leave a direct pointer.
|
|
17
|
+
- Add direct conditional pointers for all otherwise-indirect reference/script/asset files: references/dotnet-monitor.md, references/dotnet-trace-collect-linux.md, references/dotnet-trace-collect.md, references/perfcollect.md, references/perfview.md.
|
|
18
|
+
- Place approval guards immediately before complete Markdown tables so original rows remain intact.
|
|
19
|
+
- Rewrite the description to the Cratis shape (what it does, Use when, Not for) and drop references to skills that are not part of this corpus.
|
|
20
|
+
|
|
21
|
+
references/dotnet-monitor.md:
|
|
22
|
+
- Quote the dotnet-monitor trace URL containing ampersand.
|
|
23
|
+
- Prefix official tool downloads/installs with marked approval/pinned-version guidance and privileged/perfcollect examples with explicit root/container-security approval, where present.
|
|
24
|
+
|
|
25
|
+
references/dotnet-trace-collect.md:
|
|
26
|
+
- Prefix official tool downloads/installs with marked approval/pinned-version guidance and privileged/perfcollect examples with explicit root/container-security approval, where present.
|
|
27
|
+
|
|
28
|
+
references/perfcollect.md:
|
|
29
|
+
- Prefix official tool downloads/installs with marked approval/pinned-version guidance and privileged/perfcollect examples with explicit root/container-security approval, where present.
|
|
30
|
+
- Add or normalize the top Contents list from existing headings; preserve section content.
|
|
31
|
+
- Place approval guards immediately before complete Markdown tables so original rows remain intact.
|
|
32
|
+
|
|
33
|
+
references/perfview.md:
|
|
34
|
+
- Prefix official tool downloads/installs with marked approval/pinned-version guidance and privileged/perfcollect examples with explicit root/container-security approval, where present.
|
|
35
|
+
- Add or normalize the top Contents list from existing headings; preserve section content.
|
|
36
|
+
- Add marked approval and pinned-version guidance before the official direct-download/source-build fallback.
|
|
37
|
+
|
|
38
|
+
references/tool-selection.md:
|
|
39
|
+
- Adjust the moved reference-relative Markdown links to preserve their targets.
|
|
40
|
+
- Contain the section moved verbatim from SKILL.md, with a reference H1 title.
|
|
41
|
+
- Add or normalize the top Contents list from existing headings; preserve section content.
|
|
42
|
+
|
|
43
|
+
NOTICE: Add this attribution, change list, and any download/execution disclosure.
|
|
44
|
+
|
|
45
|
+
Executes or downloads (instructions retained, not executed by this import):
|
|
46
|
+
- references/tool-selection.md: 3. **`perfcollect`** — inside the container when native stacks are needed on pre-.NET 10 (requires `SYS_ADMIN` / `--privileged`).
|
|
47
|
+
- SKILL.md: 1. **Installation**: How to install the tool if it is not already available (e.g. `dotnet tool install -g dotnet-trace`). **When recommending multiple tools, provide installation and usage instructions for each one** — do not mention a tool without showing how to install and use it.
|
|
48
|
+
- SKILL.md: | `perfcollect` in container without `SYS_ADMIN` | Containers drop `SYS_ADMIN` by default. Run with `--privileged` or add `SYS_ADMIN` capability, or fall back to `dotnet-trace`. |
|
|
49
|
+
- SKILL.md: | Forgetting to install tools in container image | Add `dotnet tool install` to your Dockerfile, or use `dotnet-monitor` as a sidecar to avoid modifying the app image. |
|
|
50
|
+
- references/dotnet-monitor.md: dotnet tool install -g dotnet-monitor
|
|
51
|
+
- references/dotnet-trace-collect.md: dotnet tool install -g dotnet-trace
|
|
52
|
+
- references/dotnet-trace-collect.md: curl -JL https://aka.ms/dotnet-trace/linux-x64 -o dotnet-trace
|
|
53
|
+
- references/dotnet-trace-collect.md: curl -JL https://aka.ms/dotnet-trace/linux-arm64 -o dotnet-trace
|
|
54
|
+
- references/dotnet-trace-collect.md: curl -JL https://aka.ms/dotnet-trace/linux-musl-x64 -o dotnet-trace
|
|
55
|
+
- references/dotnet-trace-collect.md: curl -JL https://aka.ms/dotnet-trace/win-x64 -o dotnet-trace.exe
|
|
56
|
+
- references/perfcollect.md: | Container | Needs `SYS_ADMIN` / `--privileged` |
|
|
57
|
+
- references/perfcollect.md: curl -OL https://aka.ms/perfcollect
|
|
58
|
+
- references/perfcollect.md: sudo ./perfcollect install
|
|
59
|
+
- references/perfcollect.md: docker run --privileged ...
|
|
60
|
+
- references/perfcollect.md: privileged: true
|
|
61
|
+
- references/perfcollect.md: allowPrivilegeEscalation: true
|
|
62
|
+
- references/perfcollect.md: ./perfcollect install
|
|
63
|
+
- references/perfcollect.md: - ❌ In containers, requires `SYS_ADMIN` or `--privileged`
|
|
64
|
+
- references/perfview.md: Download from [https://github.com/microsoft/perfview/releases](https://github.com/microsoft/perfview/releases). PerfView is a standalone `.exe` — no installation required.
|
|
65
|
+
- references/perfview.md: > **PerfView inside containers**: `PerfView.exe` does not run in many slimmed-down Windows container images. To run PerfView inside a container (needed for the merge step in process-isolation, or for direct collection in Hyper-V), build **PerfViewCollect** from [https://github.com/microsoft/perfview](https://github.com/microsoft/perfview) as a self-contained publish, then copy the output binaries into the container.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dotnet-trace-collect
|
|
3
|
+
description: 'Guides capturing diagnostic artifacts to diagnose production .NET performance problems: choosing tools, collecting performance data, and understanding trade-offs across Windows and Linux, .NET Framework and modern .NET, and container and non-container environments. Use when the user needs help choosing a diagnostic tool or collecting performance data for a .NET process. Not for crash dumps (use dump-collect), repository-level profiling workflows (use profiling), or analyzing collected traces.'
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!-- Modified by Cratis from dotnet's original (MIT): frontmatter, applicability, navigation and the changes listed in NOTICE. Upstream: https://github.com/dotnet/skills (plugins/dotnet-diag/skills/dotnet-trace-collect/SKILL.md; see NOTICE) -->
|
|
8
|
+
|
|
9
|
+
# .NET Trace Collect
|
|
10
|
+
|
|
11
|
+
Cratis rules in `.cratis/ai/rules/` (including `csharp.md`, `specs.csharp.md`, and `orleans.md`) and the `cratis-*` skills win where they differ.
|
|
12
|
+
|
|
13
|
+
This skill helps developers diagnose production performance issues by recommending the right diagnostic tools for their environment, guiding data collection, and suggesting analysis approaches. It does not analyze code for anti-patterns or perform the analysis itself.
|
|
14
|
+
|
|
15
|
+
## When to Use
|
|
16
|
+
|
|
17
|
+
- A developer needs to investigate a production performance issue (high CPU, memory leak, slow requests, excessive GC, networking errors, etc.)
|
|
18
|
+
- Choosing the right diagnostic tool for a specific runtime, OS, or deployment topology
|
|
19
|
+
- Setting up and running diagnostic tool commands for data collection
|
|
20
|
+
- Understanding trade-offs between available tools (e.g. PerfView vs dotnet-trace)
|
|
21
|
+
- Collecting diagnostics from containerized or Kubernetes workloads
|
|
22
|
+
|
|
23
|
+
## When Not to Use
|
|
24
|
+
|
|
25
|
+
- Reviewing source code for performance anti-patterns (use a code review skill instead)
|
|
26
|
+
- Benchmarking during development (e.g. BenchmarkDotNet setup)
|
|
27
|
+
- Analyzing collected trace or dump files (this skill recommends tools for analysis, but does not perform it)
|
|
28
|
+
|
|
29
|
+
## Inputs
|
|
30
|
+
|
|
31
|
+
| Input | Required | Description |
|
|
32
|
+
|-------|----------|-------------|
|
|
33
|
+
| Symptom | Yes | What the developer is observing (high CPU, memory growth, slow requests, hangs, excessive GC, HTTP 5xx errors, networking timeouts, connection failures, assembly loading failures, etc.) |
|
|
34
|
+
| Runtime | Yes | .NET Framework or modern .NET (and version, especially whether .NET 10+) |
|
|
35
|
+
| OS | Yes | Windows or Linux |
|
|
36
|
+
| Deployment | Yes | Non-container, container, or Kubernetes |
|
|
37
|
+
| Admin privileges | Recommended | Whether the developer has admin/root access on the target machine |
|
|
38
|
+
| Repro characteristics | Recommended | Whether the issue is easy to reproduce or requires a long time to manifest |
|
|
39
|
+
|
|
40
|
+
## Workflow
|
|
41
|
+
|
|
42
|
+
### Step 1: Understand the environment
|
|
43
|
+
|
|
44
|
+
Determine or ask the developer to clarify:
|
|
45
|
+
|
|
46
|
+
1. **Symptom**: What they are observing (high CPU, memory leak, slow requests, hangs, excessive GC, HTTP 5xx errors, networking timeouts, connection failures, assembly loading failures, etc.)
|
|
47
|
+
2. **Runtime**: .NET Framework or modern .NET? If modern .NET, which version? (Especially whether .NET 10 or later.)
|
|
48
|
+
3. **OS**: Windows or Linux?
|
|
49
|
+
4. **Deployment**: Running directly on the host, in a container, or in Kubernetes?
|
|
50
|
+
5. **Admin privileges**: Do they have admin/root access on the target machine or container?
|
|
51
|
+
6. **Repro characteristics**: Does the issue reproduce quickly, or does it take a long time to manifest?
|
|
52
|
+
7. **Workload context**: Determine or ask the user if you are running in the context of the workload (i.e., on the same machine or connected to the same environment where the issue is occurring). If so, you can run diagnostic commands directly on their behalf. If not, provide the commands as guidance for the user to run themselves.
|
|
53
|
+
|
|
54
|
+
Use this information to select the right tool in Step 2.
|
|
55
|
+
|
|
56
|
+
Read references/tool-selection.md when selecting the relevant diagnostic workflow.
|
|
57
|
+
|
|
58
|
+
### Step 3: Guide data collection
|
|
59
|
+
|
|
60
|
+
Provide the specific commands for the recommended tool. Load the appropriate reference file from the [tool reference lookup](references/tool-selection.md#tool-reference-lookup) table for detailed command-line examples.
|
|
61
|
+
|
|
62
|
+
Key guidance to include:
|
|
63
|
+
|
|
64
|
+
> **Cratis:** Downloads or installs a tool: requires the user's approval; prefer a pinned version (`dotnet tool install <tool> --version <x>`)
|
|
65
|
+
1. **Installation**: How to install the tool if it is not already available (e.g. `dotnet tool install -g dotnet-trace`). **When recommending multiple tools, provide installation and usage instructions for each one** — do not mention a tool without showing how to install and use it.
|
|
66
|
+
2. **PID discovery (required before any `-p <PID>` command)**: Verify the target process first (for example: `dotnet-trace ps`, `curl <monitor-endpoint>/processes`, or `ps` inside a container). If the app is expected to be PID 1 in a container, still verify before collecting.
|
|
67
|
+
3. **Collection command**: The exact command to run, including relevant providers, output format, and duration.
|
|
68
|
+
4. **Container considerations**:
|
|
69
|
+
- Collecting from **inside** the container: ensure the tool is installed in the image or use `kubectl cp` to copy it in.
|
|
70
|
+
- Collecting from **outside** the container: use `dotnet-monitor` as a sidecar with a shared diagnostic port (Unix domain socket in `/tmp`).
|
|
71
|
+
- Kubernetes: `dotnet-monitor` as a sidecar container, or `kubectl debug` for ephemeral debug containers.
|
|
72
|
+
5. **Long-running repros** (Windows/PerfView): show how to use trigger arguments and circular buffer settings.
|
|
73
|
+
6. **Output location**: Where the collected file will be saved and how to copy it off the target for analysis.
|
|
74
|
+
7. **Artifact handoff checklist**: Include runtime version, OS/kernel, container image tag or build SHA, PID/process name, UTC collection start/end timestamps, exact command used, and final artifact path when handing traces to someone else for analysis.
|
|
75
|
+
|
|
76
|
+
### Step 4: Recommend analysis approach
|
|
77
|
+
|
|
78
|
+
After data is collected, recommend the appropriate tool for analysis. Do **not** perform the analysis — just point the developer to the right tool and documentation.
|
|
79
|
+
|
|
80
|
+
| Collected Data | Analysis Tool | Notes |
|
|
81
|
+
|----------------|---------------|-------|
|
|
82
|
+
| `.nettrace` file | PerfView (Windows), Speedscope (web) | PerfView gives the richest view on Windows |
|
|
83
|
+
| `.etl` / `.etl.zip` file | PerfView | ETW traces from PerfView or perfcollect |
|
|
84
|
+
| `perf.data.nl` from perfcollect | PerfView (Windows) | Copy the file to a Windows machine and open with PerfView |
|
|
85
|
+
|
|
86
|
+
## Validation
|
|
87
|
+
|
|
88
|
+
- [ ] The recommended tool is compatible with the developer's runtime, OS, and deployment topology
|
|
89
|
+
- [ ] The collection command runs without errors
|
|
90
|
+
- [ ] The output file is generated in the expected location
|
|
91
|
+
- [ ] The developer knows which analysis tool to use for the collected data
|
|
92
|
+
|
|
93
|
+
## Common Pitfalls
|
|
94
|
+
|
|
95
|
+
> **Cratis:** Requires the user's explicit approval: downloads and runs a script as root / changes container security.
|
|
96
|
+
> **Cratis:** Downloads or installs a tool: requires the user's approval; prefer a pinned version (`dotnet tool install <tool> --version <x>`)
|
|
97
|
+
|
|
98
|
+
| Pitfall | Solution |
|
|
99
|
+
|---------|----------|
|
|
100
|
+
| Using `dotnet-trace` on .NET Framework | `dotnet-trace` only works with modern .NET (.NET Core 3.0+). Use PerfView for .NET Framework. |
|
|
101
|
+
| PerfView without admin privileges | PerfView requires admin for ETW tracing. Fall back to `dotnet-trace` if admin is not available. |
|
|
102
|
+
| `perfcollect` in container without `SYS_ADMIN` | Containers drop `SYS_ADMIN` by default. Run with `--privileged` or add `SYS_ADMIN` capability, or fall back to `dotnet-trace`. |
|
|
103
|
+
| Huge trace files from long repros | On Windows, use PerfView `/StopOn` triggers that fire on the symptom you want to capture (e.g., `/StopOnPerfCounter`, `/StopOnGCEvent`, `/StopOnException`) with `/CircularMB` and `/BufferSizeMB`. **Never trigger on recovery** — the circular buffer continuously overwrites old data, so the interesting behavior may be lost by the time collection stops. |
|
|
104
|
+
| Diagnostic port not accessible in container | Mount `/tmp` as a shared volume between the app container and `dotnet-monitor` sidecar for the diagnostic Unix domain socket. |
|
|
105
|
+
| Forgetting to install tools in container image | Add `dotnet tool install` to your Dockerfile, or use `dotnet-monitor` as a sidecar to avoid modifying the app image. |
|
|
106
|
+
| Exposing `dotnet-monitor` with `--no-auth` in production | Keep auth enabled, bind to localhost, and use `kubectl port-forward` for access. Use `--no-auth` only for short-lived isolated debugging. |
|
|
107
|
+
| Collecting only CPU/thread-time trace for networking issues | CPU and thread-time traces alone do not show HTTP status codes, DNS timing, or connection pool behavior. Add the networking providers (`System.Net.Http`, `System.Net.NameResolution`, `System.Net.Security`, `System.Net.Sockets`) alongside the thread-time trace. |
|
|
108
|
+
| Enabling all networking providers when only one is needed | Each networking provider adds overhead. If the issue is clearly HTTP-level (5xx status codes), `System.Net.Http` alone may be sufficient. Add DNS, TLS, and socket providers when the root cause is unclear. |
|
|
109
|
+
|
|
110
|
+
## Reference navigation
|
|
111
|
+
|
|
112
|
+
- Read references/dotnet-monitor.md when working on dotnet monitor.
|
|
113
|
+
- Read references/dotnet-trace-collect-linux.md when working on dotnet trace collect linux.
|
|
114
|
+
- Read references/dotnet-trace-collect.md when working on dotnet trace collect.
|
|
115
|
+
- Read references/perfcollect.md when working on perfcollect.
|
|
116
|
+
- Read references/perfview.md when working on perfview.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# dotnet-monitor
|
|
2
|
+
|
|
3
|
+
**Purpose**: REST API-based diagnostics collection, designed for container and Kubernetes environments.
|
|
4
|
+
|
|
5
|
+
| Attribute | Value |
|
|
6
|
+
|-----------|-------|
|
|
7
|
+
| OS | Windows, Linux, macOS |
|
|
8
|
+
| Runtime | Modern .NET (.NET Core 3.1+) |
|
|
9
|
+
| .NET Framework | ❌ Not supported |
|
|
10
|
+
| Admin required | No |
|
|
11
|
+
| Container | ✅ Designed for containers/K8s — runs as a sidecar |
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# As a global tool
|
|
17
|
+
# Cratis: Downloads or installs a tool: requires the user's approval; prefer a pinned version (`dotnet tool install <tool> --version <x>`)
|
|
18
|
+
dotnet tool install -g dotnet-monitor
|
|
19
|
+
|
|
20
|
+
# As a container image (for K8s sidecar)
|
|
21
|
+
# mcr.microsoft.com/dotnet/monitor
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Common Commands
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Production-safe default: keep auth enabled (default) and bind to loopback
|
|
28
|
+
dotnet-monitor collect --urls http://127.0.0.1:52323 --metricUrls http://127.0.0.1:52325
|
|
29
|
+
|
|
30
|
+
# Dev-only shortcut in isolated environments (avoid in production)
|
|
31
|
+
dotnet-monitor collect --urls http://127.0.0.1:52323 --no-auth
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Security Guidance (Production)
|
|
35
|
+
|
|
36
|
+
- Do **not** run `dotnet-monitor` with `--no-auth` on production workloads.
|
|
37
|
+
- Bind to localhost (`127.0.0.1`) and access through `kubectl port-forward` (or another local-only tunnel).
|
|
38
|
+
- If remote access is required, keep auth enabled and restrict network exposure to trusted operators.
|
|
39
|
+
|
|
40
|
+
## REST API Endpoints
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Access via local tunnel (recommended in Kubernetes)
|
|
44
|
+
kubectl port-forward pod/<pod-name> 52323:52323
|
|
45
|
+
|
|
46
|
+
# List processes (auth enabled by default)
|
|
47
|
+
curl -H "Authorization: Bearer <monitor-token>" http://localhost:52323/processes
|
|
48
|
+
|
|
49
|
+
# Collect a trace
|
|
50
|
+
curl -H "Authorization: Bearer <monitor-token>" -o trace.nettrace "http://localhost:52323/trace?pid=<PID>&durationSeconds=30"
|
|
51
|
+
|
|
52
|
+
# Collect GC trace
|
|
53
|
+
curl -H "Authorization: Bearer <monitor-token>" -o trace.nettrace "http://localhost:52323/trace?pid=<PID>&profile=gc-verbose&durationSeconds=30"
|
|
54
|
+
|
|
55
|
+
# Collect trace with networking providers (HTTP status codes, DNS, TLS, sockets)
|
|
56
|
+
curl -H "Authorization: Bearer <monitor-token>" -o trace.nettrace "http://localhost:52323/trace?pid=<PID>&durationSeconds=30&providers=System.Net.Http,System.Net.NameResolution,System.Net.Security,System.Net.Sockets"
|
|
57
|
+
|
|
58
|
+
# Get live metrics
|
|
59
|
+
curl -H "Authorization: Bearer <monitor-token>" http://localhost:52323/livemetrics?pid=<PID>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Kubernetes Sidecar Setup
|
|
63
|
+
|
|
64
|
+
```yaml
|
|
65
|
+
# Pod spec with dotnet-monitor as sidecar
|
|
66
|
+
spec:
|
|
67
|
+
containers:
|
|
68
|
+
- name: app
|
|
69
|
+
image: myapp:latest
|
|
70
|
+
volumeMounts:
|
|
71
|
+
- name: diag
|
|
72
|
+
mountPath: /tmp
|
|
73
|
+
- name: monitor
|
|
74
|
+
image: mcr.microsoft.com/dotnet/monitor:latest
|
|
75
|
+
args: ["collect", "--urls", "http://127.0.0.1:52323", "--metricUrls", "http://127.0.0.1:52325"]
|
|
76
|
+
volumeMounts:
|
|
77
|
+
- name: diag
|
|
78
|
+
mountPath: /tmp
|
|
79
|
+
ports:
|
|
80
|
+
- containerPort: 52323
|
|
81
|
+
volumes:
|
|
82
|
+
- name: diag
|
|
83
|
+
emptyDir: {}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The shared `/tmp` volume allows `dotnet-monitor` to access the app's diagnostic Unix domain socket.
|
|
87
|
+
Keep auth enabled (default), and access the API via `kubectl port-forward` rather than exposing a public Service unless you have explicit authentication and network controls in place.
|
|
88
|
+
|
|
89
|
+
## Trade-offs
|
|
90
|
+
|
|
91
|
+
- ✅ Purpose-built for containers and Kubernetes
|
|
92
|
+
- ✅ No tools needed inside the app container
|
|
93
|
+
- ✅ REST API is easy to automate and integrate
|
|
94
|
+
- ❌ Requires sidecar setup and shared volume
|
|
95
|
+
- ❌ Additional resource overhead from sidecar container
|
|
96
|
+
- ❌ Requires authentication setup (API key or `--no-auth` flag)
|
|
97
|
+
- ⚠️ **When running in the workload context** (console access to the container), prefer console-based tools (`dotnet-trace`, `dotnet-trace collect-linux`) to avoid authentication setup. Use `dotnet-monitor` when console access is not available or when it is already deployed.
|