diff --git a/.github/actions/action-utils.js b/.github/actions/action-utils.js
index 88491c7b226..b401cf2a1ba 100644
--- a/.github/actions/action-utils.js
+++ b/.github/actions/action-utils.js
@@ -51,4 +51,4 @@ module.exports.friendlyDateFromISODate = function(isoDate) {
module.exports.splitVersionTag = splitVersionTag;
module.exports.readFile = (fileName) => util.promisify(fs.readFile)(fileName, 'utf8');
-module.exports.writeFile = (fileName, contents) => util.promisify(fs.writeFile)(fileName, contents);
\ No newline at end of file
+module.exports.writeFile = (fileName, contents) => util.promisify(fs.writeFile)(fileName, contents);
diff --git a/.github/actions/learning-path-staleness-check/action.yml b/.github/actions/learning-path-staleness-check/action.yml
new file mode 100644
index 00000000000..4e651ad6ee8
--- /dev/null
+++ b/.github/actions/learning-path-staleness-check/action.yml
@@ -0,0 +1,30 @@
+name: 'CheckLearningPathLinks Action'
+description: 'Checks the links in the learning paths for staleness'
+inputs:
+ repoURLToSearch:
+ description: 'The repo referenced in the learning path docs (in URL form)'
+ required: true
+ learningPathsDirectory:
+ description: 'The directory where the learning paths reside (e.g. documentation/learningPath)'
+ required: true
+ changedFilePaths:
+ description: 'Paths to the changed files'
+ required: false
+ sourceDirectoryName:
+ description: 'The name of the top-level directory (e.g. src) - only files inside this directory will be included in the search'
+ required: true
+ oldHash:
+ description: 'The hash currently being used by the learning path'
+ required: true
+ newHash:
+ description: 'The hash to be inserted into the updated learning path'
+ required: true
+ learningPathHashFile:
+ description: 'The file where the commit hash being used for the learning paths is kept'
+ required: true
+ excludeLinks:
+ description: 'Comma separated strings to exclude from processing'
+ required: false
+runs:
+ using: 'node16'
+ main: 'index.js'
diff --git a/.github/actions/learning-path-staleness-check/index.js b/.github/actions/learning-path-staleness-check/index.js
new file mode 100644
index 00000000000..0b8e3891711
--- /dev/null
+++ b/.github/actions/learning-path-staleness-check/index.js
@@ -0,0 +1,274 @@
+const actionUtils = require('../action-utils.js');
+const fs = require('fs');
+const path = require('path');
+const prevPathPrefix = "prev/";
+const linePrefix = "#L";
+const separator = " | ";
+
+modifiedFilesPathToLearningPathFile = {};
+modifiedFilesUrlToFileName = {};
+
+var outOfSync = new Set();
+var manuallyReview = new Set();
+var suggestions = new Set();
+var modifiedFiles = new Set();
+
+const oldNewLinkSeparator = ' -> ';
+
+function ReplaceOldWithNewText(content, oldText, newText)
+{
+ return content.replaceAll(oldText, newText);
+}
+
+function UpdateModifiedFiles(fileName, path, learningPathFile)
+{
+ modifiedFilesUrlToFileName[path] = fileName;
+
+ modifiedFilesPathToLearningPathFile[path] = modifiedFilesPathToLearningPathFile[path] ? modifiedFilesPathToLearningPathFile[path] : new Set();;
+ modifiedFilesPathToLearningPathFile[path].add(learningPathFile);
+
+ modifiedFiles = new Set();
+ for (currPath in modifiedFilesPathToLearningPathFile)
+ {
+ const fileName = modifiedFilesUrlToFileName[currPath];
+ modifiedFiles.add(AssembleModifiedFilesOutput(fileName, currPath, Array.from(modifiedFilesPathToLearningPathFile[currPath])));
+ }
+}
+
+function AssembleModifiedFilesOutput(fileName, path, learningPathFiles)
+{
+ return CreateLink(fileName, path, undefined) + separator + BoldedText(learningPathFiles.join(" "));
+}
+
+function BoldedText(text)
+{
+ return "**" + text + "**";
+}
+
+function UpdateManuallyReview(fileName, path, learningPathFile, learningPathLineNumber, lineNumber = undefined)
+{
+ manuallyReview.add(AssembleOutput(fileName, path, undefined, lineNumber, undefined, learningPathFile, learningPathLineNumber))
+}
+
+function UpdateOutOfSync(link, learningPathFile)
+{
+ outOfSync.add(link + separator + BoldedText(learningPathFile))
+}
+
+function UpdateSuggestions(fileName, oldPath, newPath, learningPathFile, learningPathLineNumber, oldLineNumber, newLineNumber)
+{
+ suggestions.add(AssembleOutput(fileName, oldPath, newPath, oldLineNumber, newLineNumber, learningPathFile, learningPathLineNumber))
+}
+
+function CreateLink(fileName, path, lineNumber)
+{
+ var codeFileLink = "[" + fileName + "]" + "(" + path + ")"
+ return AppendLineNumber(codeFileLink, lineNumber)
+}
+
+function AssembleOutput(fileName, oldPath, newPath, oldLineNumber, newLineNumber, learningPathFile, learningPathLineNumber)
+{
+ var codeFileLink = CreateLink(fileName, oldPath, oldLineNumber)
+
+ if (newPath && newLineNumber) {
+ codeFileLink += oldNewLinkSeparator + CreateLink(fileName, newPath, newLineNumber)
+ }
+
+ return codeFileLink + separator + BoldedText(AppendLineNumber(learningPathFile, learningPathLineNumber, undefined));
+}
+
+function AppendLineNumber(text, lineNumber)
+{
+ if (!lineNumber) { return text }
+
+ return text + " " + linePrefix + lineNumber
+}
+
+function CheckForEndOfLink(str, startIndex)
+{
+ const illegalCharIndex = str.substr(startIndex).search(/[\>\])\s]|$|.$|.\s/m); // This regex isn't perfect, but should cover most cases.
+ return illegalCharIndex;
+}
+
+function StripLineNumber(link, linePrefixIndex)
+{
+ return link.substring(0, linePrefixIndex);
+}
+
+function GetContent(path) {
+ try {
+ return fs.readFileSync(path, 'utf8');
+ }
+ catch (error) {}
+
+ return undefined;
+}
+
+function ConstructOutputText(core)
+{
+ var body = "";
+
+ if (manuallyReview.size > 0) { body += "
Manually Review:
" + Array.from(manuallyReview).join("
") + "
"; }
+
+ if (outOfSync.size > 0) { body += "Links With Out Of Sync Commit Hashes:
" + Array.from(outOfSync).join("
") + "
"; }
+
+ if (suggestions.size > 0) { body += "Auto-Applied Suggestions:
" + Array.from(suggestions).join("
") + "
"; }
+
+ if (modifiedFiles.size > 0) { body += "Modified Files:
" + Array.from(modifiedFiles).join("
") + "
"; }
+
+ console.log("body=" + body);
+ core.setOutput('outputText', body);
+}
+
+function ValidateLinks(learningPathContents, repoURLToSearch, modifiedPRFiles, learningPathFile, oldHash, newHash, sourceDirectoryName, excludeLinksArray)
+{
+ // Get all indices where a link to the repo is found within the current learning path file
+ var linkIndices = [];
+ for(var pos = learningPathContents.indexOf(repoURLToSearch); pos !== -1; pos = learningPathContents.indexOf(repoURLToSearch, pos + 1)) {
+ linkIndices.push(pos);
+ }
+
+ for(let startOfLink of linkIndices)
+ {
+ // Clean up the link, determine if it has a line number suffix
+ let endOfLink = startOfLink + CheckForEndOfLink(learningPathContents, startOfLink)
+ if (endOfLink < startOfLink) { endOfLink = learningPathContents.length; } // If no illegal characters are found, the link is at the end of the file
+
+ const link = learningPathContents.substring(startOfLink, endOfLink);
+
+ if (excludeLinksArray.some(excludeLink => link.toLowerCase().includes(excludeLink))) { continue; }
+
+ const pathStartIndex = link.indexOf(sourceDirectoryName);
+
+ if (pathStartIndex === -1) { continue }
+
+ if (!link.includes(oldHash))
+ {
+ UpdateOutOfSync(link, learningPathFile);
+ continue
+ }
+
+ const linePrefixIndex = link.indexOf(linePrefix);
+ const linkHasLineNumber = linePrefixIndex !== -1;
+ const pathEndIndex = linkHasLineNumber ? linePrefixIndex : endOfLink;
+
+ // Check if the file being referenced by the link is one of the modified files in the PR
+ const linkFilePath = link.substring(pathStartIndex, pathEndIndex);
+ if (modifiedPRFiles.includes(linkFilePath))
+ {
+ const fileName = linkFilePath.substring(linkFilePath.lastIndexOf('/') + 1);
+
+ UpdateModifiedFiles(fileName, linkHasLineNumber ? StripLineNumber(link, linePrefixIndex) : link, learningPathFile);
+
+ // This is the line number in the learning path file that contains the link - not the #L line number in the link itself
+ const learningPathLineNumber = learningPathContents.substring(0, startOfLink).split("\n").length;
+
+ var headContent = GetContent(linkFilePath)
+ if (!headContent) {
+ UpdateManuallyReview(fileName, link, learningPathFile, learningPathLineNumber);
+ continue
+ }
+ const headContentLines = headContent.toString().split("\n");
+
+ if (!linkHasLineNumber) { continue; }
+ const oldLineNumber = Number(link.substring(linePrefixIndex + linePrefix.length, link.length));
+
+ var prevContent = GetContent(prevPathPrefix + linkFilePath)
+ if (!prevContent) { continue; }
+ const prevContentLines = prevContent.toString().split("\n");
+
+ if (prevContentLines.length < oldLineNumber)
+ {
+ UpdateManuallyReview(fileName, link, learningPathFile, learningPathLineNumber, oldLineNumber);
+ }
+ else if (headContentLines.length < oldLineNumber || prevContentLines[oldLineNumber - 1].trim() !== headContentLines[oldLineNumber - 1].trim())
+ {
+ const newLineNumberLast = headContentLines.lastIndexOf(prevContentLines[oldLineNumber - 1]) + 1;
+ const newLineNumberFirst = headContentLines.indexOf(prevContentLines[oldLineNumber - 1]) + 1;
+
+ if (newLineNumberLast !== newLineNumberFirst) // Multiple matches found in the file
+ {
+ UpdateManuallyReview(fileName, link, learningPathFile, learningPathLineNumber, oldLineNumber);
+ }
+ else
+ {
+ let updatedLink = StripLineNumber(link.replace(oldHash, newHash), linePrefixIndex) + linePrefix + newLineNumberFirst;
+ UpdateSuggestions(fileName, link, updatedLink, learningPathFile, learningPathLineNumber, oldLineNumber, newLineNumberFirst);
+ }
+ }
+ }
+ }
+}
+
+const main = async () => {
+
+ const [core] = await actionUtils.installAndRequirePackages("@actions/core");
+
+ try {
+ const learningPathDirectory = core.getInput('learningPathsDirectory', { required: true });
+ const repoURLToSearch = core.getInput('repoURLToSearch', { required: true });
+ const changedFilePaths = core.getInput('changedFilePaths', {required: false});
+ const learningPathHashFile = core.getInput('learningPathHashFile', { required: true });
+ const sourceDirectoryName = core.getInput('sourceDirectoryName', { required: true });
+ const oldHash = core.getInput('oldHash', { required: true });
+ const newHash = core.getInput('newHash', { required: true });
+ const excludeLinks = core.getInput('excludeLinks', { required: false });
+ const excludeLinksArray = excludeLinks ? excludeLinks.split(',').map(function(item) { return item.toLowerCase().trim() }) : [];
+
+ if (changedFilePaths === null || changedFilePaths.trim() === "") { return }
+
+ // Scan each file in the learningPaths directory
+ fs.readdir(learningPathDirectory, (_, files) => {
+ files.forEach(learningPathFile => {
+ try {
+ const learningPathContents = GetContent(path.join(learningPathDirectory, learningPathFile))
+ if (learningPathContents)
+ {
+ ValidateLinks(learningPathContents, repoURLToSearch, changedFilePaths.split(' '), learningPathFile, oldHash, newHash, sourceDirectoryName, excludeLinksArray)
+ ConstructOutputText(core);
+ }
+ } catch (error) {
+ console.log("Error: " + error)
+ console.log("Could not find learning path file: " + learningPathFile)
+ }
+ });
+ });
+
+ fs.writeFileSync(learningPathHashFile, newHash);
+
+ // Scan each file in the learningPaths directory
+ fs.readdir(learningPathDirectory, (_, files) => {
+
+ files.forEach(learningPathFile => {
+ try {
+ const fullPath = path.join(learningPathDirectory, learningPathFile)
+ let content = fs.readFileSync(fullPath, 'utf8')
+
+ let suggestionsArray = Array.from(suggestions);
+ if (suggestionsArray && suggestionsArray.length > 0) {
+ suggestionsArray.forEach(suggestion => {
+ const suggestionArray = suggestion.split(oldNewLinkSeparator)
+ var oldLink = suggestionArray[0]
+ var newLink = suggestionArray[1]
+ oldLink = oldLink.substring(oldLink.indexOf('(') + 1, oldLink.lastIndexOf(')'))
+ newLink = newLink.substring(newLink.indexOf('(') + 1, newLink.lastIndexOf(')'))
+ content = ReplaceOldWithNewText(content, oldLink, newLink)
+ })
+ }
+
+ content = ReplaceOldWithNewText(content, oldHash, newHash)
+ fs.writeFileSync(fullPath, content);
+ } catch (error) {
+ console.log("Error: " + error)
+ console.log("Could not find learning path file: " + learningPathFile)
+ }
+ });
+ });
+
+ } catch (error) {
+ core.setFailed(error.message);
+ }
+}
+
+// Call the main function to run the action
+main();
diff --git a/.github/learning-path-sha.txt b/.github/learning-path-sha.txt
new file mode 100644
index 00000000000..8a50ab94965
--- /dev/null
+++ b/.github/learning-path-sha.txt
@@ -0,0 +1 @@
+341ff64a6097fe0bc66950e254e6160abcf77b84
diff --git a/.github/workflows/check-learning-path-links.yml b/.github/workflows/check-learning-path-links.yml
new file mode 100644
index 00000000000..7b9f4f0a6f9
--- /dev/null
+++ b/.github/workflows/check-learning-path-links.yml
@@ -0,0 +1,65 @@
+name: 'Check Learning Path Links'
+on:
+ schedule: # Run once a month
+ - cron: '0 0 1 * *'
+ workflow_dispatch:
+
+permissions: {}
+
+jobs:
+ check-learning-path-links:
+ name: 'Check Learning Path Links'
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ pull-requests: write
+
+ steps:
+ - name: Checkout head
+ uses: actions/checkout@v4
+ with:
+ persist-credentials: true # need this for opening a PR
+ fetch-depth: 0
+ ref: main
+
+ - name: Get previous update SHA
+ id: get_sha
+ run: |
+ prev_sha=$(cat .github/learning-path-sha.txt)
+ echo "prev_sha=$prev_sha" >> $GITHUB_ENV
+
+ - name: Checkout previous update
+ uses: actions/checkout@v4
+ with:
+ persist-credentials: false
+ ref: ${{ env.prev_sha }}
+ path: prev
+
+ - name: Get changed files
+ run: |
+ changed_source_files=$(git diff-tree --no-commit-id --name-only -r "$prev_sha" "$GITHUB_SHA" | { grep "**.cs$" || test $? = 1; })
+ echo "Files to validate: '${changed_source_files}'"
+ echo "updated_files=$(echo ${changed_source_files})" >> $GITHUB_ENV
+
+ - name: Check Learning Path Links
+ id: check-links
+ uses: ./.github/actions/learning-path-staleness-check
+ with:
+ repoURLToSearch: 'https://github.com/dotnet/dotnet-monitor'
+ learningPathsDirectory: 'documentation/learningPath'
+ changedFilePaths: ${{ env.updated_files }}
+ sourceDirectoryName: 'src'
+ oldHash: ${{ env.prev_sha }}
+ newHash: ${{ github.sha }}
+ learningPathHashFile: '.github/learning-path-sha.txt'
+
+ - name: Open PR
+ uses: ./.github/actions/open-pr
+ with:
+ files_to_commit: --all -- :!prev
+ title: "[REQUIRES MANUAL REVIEW] Update Learning Paths"
+ commit_message: Update Learning Paths
+ body: This PR was auto generated and will not be automatically merged in - adjustments should be made manually as-needed.
${{ steps.check-links.outputs.outputText }}
+ branch_name: learningPathUpdates/${{ github.sha }}
+ fail_if_files_unchanged: true
+ auth_token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/verify-dependabot-clearly-defined.yml b/.github/workflows/verify-dependabot-clearly-defined.yml
index d761be2bf95..a04f031cc37 100644
--- a/.github/workflows/verify-dependabot-clearly-defined.yml
+++ b/.github/workflows/verify-dependabot-clearly-defined.yml
@@ -14,7 +14,7 @@ jobs:
steps:
- name: Fetch Dependabot metadata
id: metadata
- uses: dependabot/fetch-metadata@c9c4182bf1b97f5224aee3906fd373f6b61b4526
+ uses: dependabot/fetch-metadata@dbb049abf0d677abbd7f7eee0375145b417fdd34
- name: Check ClearlyDefined
if: ${{steps.metadata.outputs.package-ecosystem == 'nuget'}}
diff --git a/documentation/learningPath/aks.md b/documentation/learningPath/aks.md
index 0bb619da2e2..6990c075a32 100644
--- a/documentation/learningPath/aks.md
+++ b/documentation/learningPath/aks.md
@@ -9,7 +9,7 @@ In addition to its availability as a .NET CLI tool, the `dotnet monitor` tool is
This workflow takes your local development copy of `dotnet-monitor`, patches it with a local development copy of the [.NET Core Diagnostics Repo](https://github.com/dotnet/diagnostics#net-core-diagnostics-repo), and makes it available as an image for you to consume in an ACR (Azure Container Registry). Note that there are many other ways to do this - this is meant to serve as a basic template that can be adapted to match your needs.
-1. Open `pwsh` and run the [generate-dev-sln script](https://github.com/dotnet/dotnet-monitor/blob/main/generate-dev-sln.ps1), providing a path to your local copy of the diagnostics repo.
+1. Open `pwsh` and run the [generate-dev-sln script](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/generate-dev-sln.ps1), providing a path to your local copy of the diagnostics repo.
> [!NOTE]
> If your changes do not involve the [.NET Core Diagnostics Repo](https://github.com/dotnet/diagnostics#net-core-diagnostics-repo), you don't need to complete this step.
diff --git a/documentation/learningPath/api.md b/documentation/learningPath/api.md
index de42e4e36d4..333262d5f8f 100644
--- a/documentation/learningPath/api.md
+++ b/documentation/learningPath/api.md
@@ -7,15 +7,15 @@ dotnet-monitor exposes functionality through both [collection rules](./collectio
## Adding New APIs
-The web API surface is defined by a series of controllers [here](../../src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/). It's common for an API to expose functionality also available via [Actions](./collectionrules.md#actions) and so methods in these controllers are often wrappers around a shared implementation. Each controller may have one or more attributes that configure how and where it is exposed, you can learn more about the notable controller attributes [here](#notable-controller-attributes).
+The web API surface is defined by a series of controllers [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/). It's common for an API to expose functionality also available via [Actions](./collectionrules.md#actions) and so methods in these controllers are often wrappers around a shared implementation. Each controller may have one or more attributes that configure how and where it is exposed, you can learn more about the notable controller attributes [here](#notable-controller-attributes).
-If the new API needs to either accept or return structured data, a dedicated model should be used. Models are defined [here](../../src/Microsoft.Diagnostics.Monitoring.WebApi/Models/).
+If the new API needs to either accept or return structured data, a dedicated model should be used. Models are defined [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/).
When adding a new API, it's important to also update the [`openapi.json`](../openapi.json) spec which describes the API surface. There are CI tests that will ensure this file has been updated to reflect any API changes. Learn more about updating `openapi.json` [here](./testing.md#openapi-generation).
### Adding Tests
-Web APIs in dotnet-monitor are typically tested using functional tests that leverage the [ApiClient](../../src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/HttpApi/ApiClient.cs) to call a specific API. Learn more about how the functional tests are defined and operate [here](./testing.md#functional-tests).
+Web APIs in dotnet-monitor are typically tested using functional tests that leverage the [ApiClient](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/HttpApi/ApiClient.cs) to call a specific API. Learn more about how the functional tests are defined and operate [here](./testing.md#functional-tests).
## Notable Controller Attributes
@@ -35,6 +35,6 @@ dotnet-monitor supports multiple different [authentication modes](../authenticat
### Determining Authentication Mode
-When dotnet-monitor starts, the command line arguments are first inspected to see if a specific authentication mode was set (such as `--no-auth`), referred to as the `StartupAuthenticationMode`, this is calculated [here](../../src/Tools/dotnet-monitor/Commands/CollectCommandHandler.cs#L27). If no modes were explicitly set via a command line argument, dotnet-monitor will select `Deferred` as the `StartupAuthenticationMode`. This indicates that the user configuration should be looked at to determine the authentication mode later on in the startup process.
+When dotnet-monitor starts, the command line arguments are first inspected to see if a specific authentication mode was set (such as `--no-auth`), referred to as the `StartupAuthenticationMode`, this is calculated [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/Commands/CollectCommandHandler.cs#L29). If no modes were explicitly set via a command line argument, dotnet-monitor will select `Deferred` as the `StartupAuthenticationMode`. This indicates that the user configuration should be looked at to determine the authentication mode later on in the startup process.
-After determining the `StartupAuthenticationMode` mode, the relevant [IAuthenticationConfigurator](../../src/Tools/dotnet-monitor/Auth/IAuthenticationConfigurator.cs) is created by the [AuthConfiguratorFactory](../../src/Tools/dotnet-monitor/Auth/AuthConfiguratorFactory.cs). This factory also handles deciding what authentication mode to use when `StartupAuthenticationMode` is `Deferred`. The selected configurator is used to configure various parts of dotnet-monitor that are specific to authentication, such as protecting the web APIs, add authentication-mode specific logging, and configuring the built-in Swagger UI.
+After determining the `StartupAuthenticationMode` mode, the relevant [IAuthenticationConfigurator](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/Auth/IAuthenticationConfigurator.cs) is created by the [AuthConfiguratorFactory](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/Auth/AuthConfiguratorFactory.cs). This factory also handles deciding what authentication mode to use when `StartupAuthenticationMode` is `Deferred`. The selected configurator is used to configure various parts of dotnet-monitor that are specific to authentication, such as protecting the web APIs, add authentication-mode specific logging, and configuring the built-in Swagger UI.
diff --git a/documentation/learningPath/collectionrules.md b/documentation/learningPath/collectionrules.md
index 6ea6c9ce47e..e1d33904df7 100644
--- a/documentation/learningPath/collectionrules.md
+++ b/documentation/learningPath/collectionrules.md
@@ -32,49 +32,49 @@ graph LR
### Key Areas Of The Code
-* Collection rules are registered [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs#L100). When adding a new trigger or action, these types need to be added here to take effect. This section is also responsible for making sure options get configured and validated.
-* Options for collection rules can be found [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Options/CollectionRuleOptions.cs).
-* Rules are applied, removed, and restarted in response to configuration changes [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/CollectionRuleService.cs). This is also responsible for generating a description of each collection rule's state for the `/collectionrules` API Endpoint.
-* The pipeline responsible for the lifetime of a single executing collection rule can be found [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/CollectionRulePipeline.cs#L55).
-* To run collection rules, `dotnet monitor` must be in `Listen` mode - this is set via [DiagnosticPortOptions](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Microsoft.Diagnostics.Monitoring.Options/DiagnosticPortOptions.cs).
+* Collection rules are registered [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs#L140). When adding a new trigger or action, these types need to be added here to take effect. This section is also responsible for making sure options get configured and validated.
+* Options for collection rules can be found [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Options/CollectionRuleOptions.cs).
+* Rules are applied, removed, and restarted in response to configuration changes [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/CollectionRuleService.cs). This is also responsible for generating a description of each collection rule's state for the `/collectionrules` API Endpoint.
+* The pipeline responsible for the lifetime of a single executing collection rule can be found [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/CollectionRulePipeline.cs#L54).
+* To run collection rules, `dotnet monitor` must be in `Listen` mode - this is set via [DiagnosticPortOptions](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.Options/DiagnosticPortOptions.cs).
* For each type of trigger, the [dotnet diagnostics repo](https://github.com/dotnet/diagnostics/blob/v6.0.351802/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/ITraceEventTrigger.cs#L29) is responsible for determining whether the triggering conditions have been satisfied.
### Triggers
-A trigger will monitor for a specific condition in the target application and raise a notification when that condition has been observed. Options for triggers can be found [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Options/CollectionRuleTriggerOptions.cs); the type of `Settings` is determined by which trigger is being used (possible trigger types can be found [here](https://github.com/dotnet/dotnet-monitor/tree/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Options/Triggers)). The interface for all triggers can be found [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Triggers/ICollectionRuleTrigger.cs) - this allows `dotnet monitor` to start and stop triggers, regardless of the trigger's properties. The collection rule pipeline creates instances of triggers [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/CollectionRulePipeline.cs#L100) before waiting for the trigger to [satisfy its conditions](https://github.com/dotnet/diagnostics/blob/v6.0.351802/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/Pipelines/TraceEventTriggerPipeline.cs#L107) - each trigger has its own set of criteria that determines when a trigger has been satisfied.
+A trigger will monitor for a specific condition in the target application and raise a notification when that condition has been observed. Options for triggers can be found [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Options/CollectionRuleTriggerOptions.cs); the type of `Settings` is determined by which trigger is being used (possible trigger types can be found [here](https://github.com/dotnet/dotnet-monitor/tree/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Options/Triggers)). The interface for all triggers can be found [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Triggers/ICollectionRuleTrigger.cs) - this allows `dotnet monitor` to start and stop triggers, regardless of the trigger's properties. The collection rule pipeline creates instances of triggers [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/CollectionRulePipeline.cs#L99) before waiting for the trigger to [satisfy its conditions](https://github.com/dotnet/diagnostics/blob/v6.0.351802/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/Pipelines/TraceEventTriggerPipeline.cs#L107) - each trigger has its own set of criteria that determines when a trigger has been satisfied.
### Actions
-Actions allow executing an operation or an external executable in response to a trigger condition being satisfied. Options for actions can be found [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Options/CollectionRuleActionOptions.cs); the type of `Settings` is determined by which action is being used (possible action types can be found [here](https://github.com/dotnet/dotnet-monitor/tree/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Options/Actions)). The interface for all actions can be found [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Actions/ICollectionRuleAction.cs) - this allows `dotnet monitor` to start an action, wait for it to complete, and get its output values regardless of the action's properties. The action list is [executed](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/CollectionRulePipeline.cs#L150) once the triggering condition has been met (assuming the action list isn't throttled), with each action by default starting without waiting for prior actions to complete.
+Actions allow executing an operation or an external executable in response to a trigger condition being satisfied. Options for actions can be found [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Options/CollectionRuleActionOptions.cs); the type of `Settings` is determined by which action is being used (possible action types can be found [here](https://github.com/dotnet/dotnet-monitor/tree/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Options/Actions)). The interface for all actions can be found [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Actions/ICollectionRuleAction.cs) - this allows `dotnet monitor` to start an action, wait for it to complete, and get its output values regardless of the action's properties. The action list is [executed](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/CollectionRulePipeline.cs#L149) once the triggering condition has been met (assuming the action list isn't throttled), with each action by default starting without waiting for prior actions to complete.
### Filters
-Filters can optionally be applied to a collection rule to choose which processes can trigger the rule. This uses the same set of [options](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Microsoft.Diagnostics.Monitoring.Options/ProcessFilterOptions.cs#L47) as setting the default process for `dotnet-monitor`. When starting a collection rule, [these filters are used to check if the current process should have the collection rule applied to it](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/CollectionRuleContainer.cs#L189); if so, the collection rule starts.
+Filters can optionally be applied to a collection rule to choose which processes can trigger the rule. This uses the same set of [options](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.Options/ProcessFilterOptions.cs#L47) as setting the default process for `dotnet-monitor`. When starting a collection rule, [these filters are used to check if the current process should have the collection rule applied to it](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/CollectionRuleContainer.cs#L187); if so, the collection rule starts.
### Limits
-Limits can optionally be applied to a collection rule to constrain the lifetime of the rule and how often its actions can be run before being throttled. Options for limits can be found [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Options/CollectionRuleLimitsOptions.cs). When provided (or when using default values), limits are evaluated in the collection rule pipeline while running. `RuleDuration` is used to [create a token](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/CollectionRulePipeline.cs#L80) that shuts down the pipeline. `ActionCountSlidingWindowDuration` does not rely on setting cancellation tokens; rather, the number of executions within the sliding window are checked on-demand [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Microsoft.Diagnostics.Monitoring.WebApi/CollectionRulePipelineState.cs#L212), and `ActionCount` is referenced to determine whether the rule needs to [terminate](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Microsoft.Diagnostics.Monitoring.WebApi/CollectionRulePipelineState.cs#L195) or [throttle](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Microsoft.Diagnostics.Monitoring.WebApi/CollectionRulePipelineState.cs#L235).
+Limits can optionally be applied to a collection rule to constrain the lifetime of the rule and how often its actions can be run before being throttled. Options for limits can be found [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Options/CollectionRuleLimitsOptions.cs). When provided (or when using default values), limits are evaluated in the collection rule pipeline while running. `RuleDuration` is used to [create a token](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/CollectionRulePipeline.cs#L79) that shuts down the pipeline. `ActionCountSlidingWindowDuration` does not rely on setting cancellation tokens; rather, the number of executions within the sliding window are checked on-demand [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.WebApi/CollectionRulePipelineState.cs#L211), and `ActionCount` is referenced to determine whether the rule needs to [terminate](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.WebApi/CollectionRulePipelineState.cs#L194) or [throttle](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.WebApi/CollectionRulePipelineState.cs#L234).
## Miscellaneous
### Trigger Shortcuts
-Trigger Shortcuts provide improved defaults, range validation, and a simpler syntax for [several commonly used `EventCounter` triggers](https://github.com/dotnet/dotnet-monitor/tree/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Options/Triggers/EventCounterShortcuts). These shortcuts provide the same functionality as using the standard `EventCounter` syntax, but have fewer available options (since there is no need to specify the `ProviderName` or the `CounterName`) - as a result, shortcuts do not inherit from `EventCounterOptions`, but rather [IEventCounterShortcuts](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Options/Triggers/EventCounterShortcuts/IEventCounterShortcuts.cs). Each type of shortcut is registered independently [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs#L117). After binding with configuration and undergoing validation, shortcuts are then converted to be treated as `EventCounter` triggers [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventCounterTriggerFactory.cs), using their respective defaults instead of the generic ones.
+Trigger Shortcuts provide improved defaults, range validation, and a simpler syntax for [several commonly used `EventCounter` triggers](https://github.com/dotnet/dotnet-monitor/tree/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Options/Triggers/EventCounterShortcuts). These shortcuts provide the same functionality as using the standard `EventCounter` syntax, but have fewer available options (since there is no need to specify the `ProviderName` or the `CounterName`) - as a result, shortcuts do not inherit from `EventCounterOptions`, but rather [IEventCounterShortcuts](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Options/Triggers/EventCounterShortcuts/IEventCounterShortcuts.cs). Each type of shortcut is registered independently [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs#L158). After binding with configuration and undergoing validation, shortcuts are then converted to be treated as `EventCounter` triggers [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventCounterTriggerFactory.cs), using their respective defaults instead of the generic ones.
### Templates
-Templates allow users to design reusable collection rule components by associating a name with a piece of configuration. Options for templates can be found [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Options/TemplateOptions.cs). Before collection rules undergo validation, `dotnet monitor` checks to see if any of the rule's components in configuration [list the name of a template](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRulePostConfigureNamedOptions.cs) - if so, the collection rule's options are populated from the correspondingly named template. Note that templates undergo the same binding process for triggers/actions as collection rules; however, since templates are treated as separate parts of configuration, this binding instead happens [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Configuration/TemplatesConfigureNamedOptions.cs).
+Templates allow users to design reusable collection rule components by associating a name with a piece of configuration. Options for templates can be found [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Options/TemplateOptions.cs). Before collection rules undergo validation, `dotnet monitor` checks to see if any of the rule's components in configuration [list the name of a template](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRulePostConfigureNamedOptions.cs) - if so, the collection rule's options are populated from the correspondingly named template. Note that templates undergo the same binding process for triggers/actions as collection rules; however, since templates are treated as separate parts of configuration, this binding instead happens [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Configuration/TemplatesConfigureNamedOptions.cs).
### Collection Rule Defaults
-Defaults can be used to limit the verbosity of configuration, allowing frequently used values for collection rules to be assigned as defaults. Options for collection rule defaults can be found [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Options/CollectionRuleDefaultsOptions.cs). These defaults are merged with the user's provided configuration [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Tools/dotnet-monitor/CollectionRules/Options/DefaultCollectionRulePostConfigureOptions.cs) - any properties that the user hasn't set (that have corresponding default values) will be updated at this point to use the default values. This step occurs prior to `dotnet monitor` attempting to use its built-in defaults, which allows user defaults to take precedence.
+Defaults can be used to limit the verbosity of configuration, allowing frequently used values for collection rules to be assigned as defaults. Options for collection rule defaults can be found [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Options/CollectionRuleDefaultsOptions.cs). These defaults are merged with the user's provided configuration [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/CollectionRules/Options/DefaultCollectionRulePostConfigureOptions.cs) - any properties that the user hasn't set (that have corresponding default values) will be updated at this point to use the default values. This step occurs prior to `dotnet monitor` attempting to use its built-in defaults, which allows user defaults to take precedence.
### Collection Rule API Endpoint
-The Collection Rule API Endpoint allows users to get information about the state of their collection rules, providing general information [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs#L532) and more specific information about a particular rule [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs#L557). **This API is solely for viewing the current state of rules, not altering state**.
+The Collection Rule API Endpoint allows users to get information about the state of their collection rules, providing general information [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs#L525) and more specific information about a particular rule [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs#L550). **This API is solely for viewing the current state of rules, not altering state**.
-Each collection rule pipeline has a [state holder](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/src/Microsoft.Diagnostics.Monitoring.WebApi/CollectionRulePipelineState.cs) that keeps track of the rule's execution. By keeping track of the pipeline's state in real-time, this state doesn't need to be calculated in response to a user hitting the `/collectionrules` endpoint. However, other user-facing information, such as countdowns, are calculated on-demand - these values are solely for display purposes and not used by `dotnet-monitor` when determining when to change state (see [Limits](#limits) for more information).
+Each collection rule pipeline has a [state holder](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.WebApi/CollectionRulePipelineState.cs) that keeps track of the rule's execution. By keeping track of the pipeline's state in real-time, this state doesn't need to be calculated in response to a user hitting the `/collectionrules` endpoint. However, other user-facing information, such as countdowns, are calculated on-demand - these values are solely for display purposes and not used by `dotnet-monitor` when determining when to change state (see [Limits](#limits) for more information).
## Keeping Documentation Up-To-Date
-When making changes to collection rules that require updates to configuration, these changes should be added [here](https://github.com/dotnet/dotnet-monitor/blob/v7.0.1/documentation/configuration.md#collection-rule-configuration). Additional information on collection rules and examples can be provided [here](https://github.com/dotnet/dotnet-monitor/tree/v7.0.1/documentation/collectionrules).
+When making changes to collection rules that require updates to configuration, these changes should be added [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/documentation/configuration/collection-rule-configuration.md). Additional information on collection rules and examples can be provided [here](https://github.com/dotnet/dotnet-monitor/tree/341ff64a6097fe0bc66950e254e6160abcf77b84/documentation/collectionrules).
diff --git a/documentation/learningPath/configuration.md b/documentation/learningPath/configuration.md
index 53242df9928..728b4582255 100644
--- a/documentation/learningPath/configuration.md
+++ b/documentation/learningPath/configuration.md
@@ -6,22 +6,22 @@
## How Configuration Works
-`dotnet-monitor` accepts configuration from several different sources, and must [combine these sources for the host builder](https://github.com/dotnet/dotnet-monitor/blob/ba8c36235943562581b666e74ef07954313eda56/src/Tools/dotnet-monitor/HostBuilder/HostBuilderHelper.cs#L46). Configuration sources are added in the order of lowest to highest precedence - meaning that if there is a conflict between a property in two configuration sources, the property found in the latter configuration source will be used.
+`dotnet-monitor` accepts configuration from several different sources, and must [combine these sources for the host builder](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/HostBuilder/HostBuilderHelper.cs#L47). Configuration sources are added in the order of lowest to highest precedence - meaning that if there is a conflict between a property in two configuration sources, the property found in the latter configuration source will be used.
-To see the merged configuration, the user can run the `config show` command (see [here](https://github.com/dotnet/dotnet-monitor/blob/ba8c36235943562581b666e74ef07954313eda56/src/Tools/dotnet-monitor/Program.cs#L69) and [here](https://github.com/dotnet/dotnet-monitor/blob/ba8c36235943562581b666e74ef07954313eda56/src/Tools/dotnet-monitor/Commands/ConfigShowCommandHandler.cs)); the `--show-sources` flag can be used to reveal which configuration source is responsible for each property. The `config show` command's output is [written out as JSON](https://github.com/dotnet/dotnet-monitor/blob/ba8c36235943562581b666e74ef07954313eda56/src/Tools/dotnet-monitor/ConfigurationJsonWriter.cs); this section must be manually updated whenever new options are added (or existing options are changed).
+To see the merged configuration, the user can run the `config show` command (see [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/Program.cs#L68) and [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/Commands/ConfigShowCommandHandler.cs)); the `--show-sources` flag can be used to reveal which configuration source is responsible for each property. The `config show` command's output is [written out as JSON](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/ConfigurationJsonWriter.cs); this section must be manually updated whenever new options are added (or existing options are changed).
-Once configuration has been merged, any singletons that have been added to the `IServiceCollection` (see [here](https://github.com/dotnet/dotnet-monitor/blob/ba8c36235943562581b666e74ef07954313eda56/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs) and [here](https://github.com/dotnet/dotnet-monitor/blob/ba8c36235943562581b666e74ef07954313eda56/src/Tools/dotnet-monitor/Commands/CollectCommandHandler.cs#L80)), such as `IConfigureOptions`, `IPostConfigureOptions`, and `IValidateOptions`, are called when an object of that type is first used, **not on startup**. This step is often used to incorporate defaults for properties that were not explicitly set by configuration, or to validate that options were set correctly.
+Once configuration has been merged, any singletons that have been added to the `IServiceCollection` (see [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs) and [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/Commands/CollectCommandHandler.cs#L85)), such as `IConfigureOptions`, `IPostConfigureOptions`, and `IValidateOptions`, are called when an object of that type is first used, **not on startup**. This step is often used to incorporate defaults for properties that were not explicitly set by configuration, or to validate that options were set correctly.
-Any changes to the configuration need to be propagated to the [schema](https://github.com/dotnet/dotnet-monitor/blob/ba8c36235943562581b666e74ef07954313eda56/documentation/schema.json). **The updated schema should be generated automatically; you should never need to manually edit the JSON.** To update the schema in Visual Studio:
-* Set [Microsoft.Diagnostics.Monitoring.ConfigurationSchema](https://github.com/dotnet/dotnet-monitor/tree/ba8c36235943562581b666e74ef07954313eda56/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema) as the startup project
+Any changes to the configuration need to be propagated to the [schema](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/documentation/schema.json). **The updated schema should be generated automatically; you should never need to manually edit the JSON.** To update the schema in Visual Studio:
+* Set [Microsoft.Diagnostics.Monitoring.ConfigurationSchema](https://github.com/dotnet/dotnet-monitor/tree/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema) as the startup project
* Build the project, with a single command-line argument for the schema's absolute path
-* Validate that the schema was correctly updated using the tests in [Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests](https://github.com/dotnet/dotnet-monitor/tree/ba8c36235943562581b666e74ef07954313eda56/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests)
+* Validate that the schema was correctly updated using the tests in [Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests](https://github.com/dotnet/dotnet-monitor/tree/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests)
## Keeping Documentation Up-To-Date
-Our configuration is primarily documented [here](https://github.com/dotnet/dotnet-monitor/tree/main/documentation/configuration). Sections are typically comprised of:
+Our configuration is primarily documented [here](https://github.com/dotnet/dotnet-monitor/tree/341ff64a6097fe0bc66950e254e6160abcf77b84/documentation/configuration). Sections are typically comprised of:
* A brief overview of the feature that is being configured
* Configuration samples in all supported formats
* A list of properties with descriptions, types, and whether a property is required
-Types are defined in [definitions.md](https://github.com/dotnet/dotnet-monitor/blob/main/documentation/api/definitions.md), and additional information about configuring collection rules can be found in the [collection rules](https://github.com/dotnet/dotnet-monitor/blob/main/documentation/collectionrules) directory. Where appropriate, indicate if configuration only pertains to a specific version of `dotnet-monitor` (e.g. `7.0+`).
+Types are defined in [definitions.md](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/documentation/api/definitions.md), and additional information about configuring collection rules can be found in the [collection rules](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/documentation/collectionrules) directory. Where appropriate, indicate if configuration only pertains to a specific version of `dotnet-monitor` (e.g. `7.0+`).
diff --git a/documentation/learningPath/egress.md b/documentation/learningPath/egress.md
index db4d712c490..5d44d615f5b 100644
--- a/documentation/learningPath/egress.md
+++ b/documentation/learningPath/egress.md
@@ -26,11 +26,11 @@ graph LR
class ide2 altColor
```
-1. [User initiates collection of artifact with a designated egress provider](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperation.cs#L49)
-1. [Locate extension's executable and manifest](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Tools/dotnet-monitor/Extensibility/ExtensionDiscoverer.cs#L28)
-1. [Start extension and pass configuration/artifact via StdIn to the other process](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Tools/dotnet-monitor/Egress/Extension/EgressExtension.cs#L102)
-1. [Connect to egress provider using configuration and send artifact](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Extensions/AzureBlobStorage/AzureBlobEgressProvider.cs#L35)
-1. [Provide success/failure information via StdOut to dotnet-monitor](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Microsoft.Diagnostics.Monitoring.Extension.Common/EgressHelper.cs#L77)
+1. [User initiates collection of artifact with a designated egress provider](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperation.cs#L45)
+1. [Locate extension's executable and manifest](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/Extensibility/ExtensionDiscoverer.cs#L28)
+1. [Start extension and pass configuration/artifact via StdIn to the other process](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/Egress/Extension/EgressExtension.cs#L102)
+1. [Connect to egress provider using configuration and send artifact](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Extensions/AzureBlobStorage/AzureBlobEgressProvider.cs#L36)
+1. [Provide success/failure information via StdOut to dotnet-monitor](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.Extension.Common/EgressHelper.cs#L77)
## Distribution and Acquisition Model
@@ -41,7 +41,7 @@ There are two versions of the `dotnet-monitor` image being offered: `monitor` an
### Well Known Egress Provider Locations
-There are 3 [locations](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs#L260) that `dotnet-monitor` scans when looking for the extensions directory (the highest priority location is listed first):
+There are 3 [locations](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs#L279) that `dotnet-monitor` scans when looking for the extensions directory (the highest priority location is listed first):
- Next to the executing `dotnet-monitor` assembly
- SharedConfigDirectory
- On Windows, `%ProgramData%\dotnet-monitor`
@@ -59,23 +59,23 @@ The distribution/acquisition model for third-party egress providers is determine
### Extension Manifest
-All extensions must include a manifest titled [`extension.json`](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Extensions/AzureBlobStorage/extension.json) that provides `dotnet-monitor` with some basic information about the extension.
+All extensions must include a manifest titled [`extension.json`](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Extensions/AzureBlobStorage/extension.json) that provides `dotnet-monitor` with some basic information about the extension.
| Name | Required | Type | Description |
|---|---|---|---|
| `Name` | true | string | The name of the extension (e.g. AzureBlobStorage) that users will use when writing configuration for the egress provider. |
| `ExecutableFileName` | false | string | If specified, the executable file (without extension) to be launched when executing the extension; either `AssemblyFileName` or `ExecutableFileName` must be specified. |
| `AssemblyFileName` | false | string | If specified, executes the extension using the shared .NET host (e.g. dotnet.exe) with the specified entry point assembly (without extension); either `AssemblyFileName` or `ExecutableFileName` must be specified. |
-| `Modes` | false | [[ExtensionMode](../api/definitions.md#extensionmode)] | Additional modes the extension can be configured to run in (see an example of Validation [here](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Microsoft.Diagnostics.Monitoring.Extension.Common/EgressHelper.cs#L80)). |
+| `Modes` | false | [[ExtensionMode](../api/definitions.md#extensionmode)] | Additional modes the extension can be configured to run in (see an example of Validation [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.Extension.Common/EgressHelper.cs#L80)). |
### Configuration
Extensions are designed to receive all user configuration through `dotnet monitor` - the extension itself should not rely on any additional configuration sources.
-In addition to the configuration provided specifically for your egress provider, `dotnet-monitor` also includes the values stored in [`Properties`](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Microsoft.Diagnostics.Monitoring.Options/EgressOptions.cs#L21). Note that `Properties` may include information that is not relevant to the current egress provider, since it is a shared bucket between all configured egress providers.
+In addition to the configuration provided specifically for your egress provider, `dotnet-monitor` also includes the values stored in [`Properties`](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.Options/EgressOptions.cs#L21). Note that `Properties` may include information that is not relevant to the current egress provider, since it is a shared bucket between all configured egress providers.
### Communicating With Dotnet-Monitor
-[`dotnet monitor` will pass serialized configuration via `StdIn` to the extension](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Tools/dotnet-monitor/Egress/Extension/EgressExtension.cs#L182); an example of how the `AzureBlobStorage` egress provider interprets the egress payload can be found [here](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Microsoft.Diagnostics.Monitoring.Extension.Common/EgressHelper.cs#L139). **It's important to validate the version number at the beginning of the stream; if an extension does not have the same version as `dotnet-monitor`, it should not attempt to continue reading from the stream, and users may need to update to a newer version of the extension.**
+[`dotnet monitor` will pass serialized configuration via `StdIn` to the extension](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/Egress/Extension/EgressExtension.cs#L182); an example of how the `AzureBlobStorage` egress provider interprets the egress payload can be found [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.Extension.Common/EgressHelper.cs#L141). **It's important to validate the version number at the beginning of the stream; if an extension does not have the same version as `dotnet-monitor`, it should not attempt to continue reading from the stream, and users may need to update to a newer version of the extension.**
-All output from the extension will be passed back to `dotnet-monitor`; this is logged [here](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Tools/dotnet-monitor/Egress/Extension/EgressExtension.OutputParser.cs#L62). The contents of the `StandardOutput` and `StandardError` streams are handled and logged as seen [here](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Tools/dotnet-monitor/Egress/Extension/EgressExtension.OutputParser.cs#L32), with the `StandardOutput` stream being logged at the `Info` level and the `StandardError` stream being logged at the `Warning` level. `Dotnet-Monitor` will continue reading output until it receives a [result](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Tools/dotnet-monitor/Egress/Extension/EgressArtifactResult.cs) from the extension via the `StandardOutput` stream, at which point the extension's process will be terminated and `dotnet-monitor` will display the appropriate log message depending on the success/failure of the operation. Exceptions thrown during the egress operation are caught [here](https://github.com/dotnet/dotnet-monitor/blob/289105261537f3977f7d1886f936d19bb3639d46/src/Microsoft.Diagnostics.Monitoring.Extension.Common/EgressHelper.cs#L53); this allows the extension to report a failure message back to `dotnet-monitor` that will be displayed to the user.
+All output from the extension will be passed back to `dotnet-monitor`; this is logged [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/Egress/Extension/EgressExtension.OutputParser.cs#L62). The contents of the `StandardOutput` and `StandardError` streams are handled and logged as seen [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/Egress/Extension/EgressExtension.OutputParser.cs#L32), with the `StandardOutput` stream being logged at the `Info` level and the `StandardError` stream being logged at the `Warning` level. `Dotnet-Monitor` will continue reading output until it receives a [result](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tools/dotnet-monitor/Egress/Extension/EgressArtifactResult.cs) from the extension via the `StandardOutput` stream, at which point the extension's process will be terminated and `dotnet-monitor` will display the appropriate log message depending on the success/failure of the operation. Exceptions thrown during the egress operation are caught [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.Extension.Common/EgressHelper.cs#L71); this allows the extension to report a failure message back to `dotnet-monitor` that will be displayed to the user.
diff --git a/documentation/learningPath/testing.md b/documentation/learningPath/testing.md
index 38a36633348..0d7d0034ad6 100644
--- a/documentation/learningPath/testing.md
+++ b/documentation/learningPath/testing.md
@@ -7,81 +7,81 @@
Tests can be executed with the command line (via [build.cmd](../../Build.cmd) -test), as part of the PR build, or in Visual Studio. Note that because of limited resources in the build pool, tests ran from the command line or in the build pool are serialized. This avoids test failures associated with parallel testing. Visual Studio does not have such restrictions and is best used for individual tests and test investigations. When running from the command line, using the `-testgroup` parameter can be used to limit the amount of tests executed. For example `build.cmd -test -testgroup PR` will run the same tests as the PR build.
-The framework of the test assemblies is controlled by [TestTargetFrameworks](../../eng/Versions.props). The test itself is attributed with a particular framework based on the [TargetFrameworkMonikerTraitAttribute](../../src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/TargetFrameworkMonikerTraitAttribute.cs).
+The framework of the test assemblies is controlled by [TestTargetFrameworks](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/eng/Versions.props). The test itself is attributed with a particular framework based on the [TargetFrameworkMonikerTraitAttribute](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/TargetFrameworkMonikerTraitAttribute.cs).
## Unit Tests
-- [Microsoft.Diagnostics.Monitoring.Tool.UnitTests](../../src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests)
-- [Microsoft.Diagnostics.Monitoring.WebApi.UnitTests](../../src/Tests/Microsoft.Diagnostics.Monitoring.WebApi.UnitTests/)
-- [CollectionRuleActions.UnitTests](../../src/Tests/CollectionRuleActions.UnitTests/)
+- [Microsoft.Diagnostics.Monitoring.Tool.UnitTests](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests)
+- [Microsoft.Diagnostics.Monitoring.WebApi.UnitTests](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.WebApi.UnitTests/)
+- [CollectionRuleActions.UnitTests](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/CollectionRuleActions.UnitTests/)
Unit test assemblies directly reference types from various dotnet-monitor assemblies. However, since most of dotnet-monitor heavily relies on code injection, there are utility classes to simplify unit test creation.
-- [TestHostHelper](../../src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/TestHostHelper.cs) can be used to setup a basic unit test scenario using dependency injection.
-- [CollectionRuleOptionsExtensions](../../src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/Options/CollectionRuleOptionsExtensions.cs) can be used to easily create collection rules from configuration.
+- [TestHostHelper](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/TestHostHelper.cs) can be used to setup a basic unit test scenario using dependency injection.
+- [CollectionRuleOptionsExtensions](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/Options/CollectionRuleOptionsExtensions.cs) can be used to easily create collection rules from configuration.
## Functional Tests
-- [Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests](../../src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests)
-- [Microsoft.Diagnostics.Monitoring.UnitTestApp](../../src/Tests/Microsoft.Diagnostics.Monitoring.UnitTestApp/)
+- [Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests)
+- [Microsoft.Diagnostics.Monitoring.UnitTestApp](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTestApp/)
Functional tests are composed of 3 main parts:
1. The test itself, which sets up and validates the results.
1. An instance of dotnet-monitor
1. An instance of an application that is being monitored (from the UnitTestApp assembly)
-* [ScenarioRunner](../../src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Runners/ScenarioRunner.cs) is typically used to orchestrate test runs. The class will spawn both an instance of dotnet-monitor and an instance of test application. The app and the test communicate via stdio. The test communicates with dotnet-monitor via its Api surface.
-* The dotnet-monitor Api surface can be accessed through the [ApiClient](../../src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/HttpApi/ApiClient.cs).
-* New scenarios can be added [here](../../src/Tests/Microsoft.Diagnostics.Monitoring.UnitTestApp/Scenarios/).
-* The [AsyncWaitScenario](../../src/Tests/Microsoft.Diagnostics.Monitoring.UnitTestApp/Scenarios/AsyncWaitScenario.cs) is sufficient for most tests.
-* Coordination of the scenario and the test is done via message passing (json over stdio) between the test and the app. To send messages to the app from the test, [AppRunner](../../src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/Runners/AppRunner.cs)'s `SendCommandAsync` is used. In the scenario definition, [ScenarioHelpers](../../src/Tests/Microsoft.Diagnostics.Monitoring.UnitTestApp/ScenarioHelpers.cs)'s `WaitForCommandAsync` is used. This can be used to synchronize various points of the test application with the execution of the dotnet-monitor Api from the test itself.
+* [ScenarioRunner](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/Runners/ScenarioRunner.cs) is typically used to orchestrate test runs. The class will spawn both an instance of dotnet-monitor and an instance of test application. The app and the test communicate via stdio. The test communicates with dotnet-monitor via its Api surface.
+* The dotnet-monitor Api surface can be accessed through the [ApiClient](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests/HttpApi/ApiClient.cs).
+* New scenarios can be added [here](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTestApp/Scenarios/).
+* The [AsyncWaitScenario](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTestApp/Scenarios/AsyncWaitScenario.cs) is sufficient for most tests.
+* Coordination of the scenario and the test is done via message passing (json over stdio) between the test and the app. To send messages to the app from the test, [AppRunner](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/Runners/AppRunner.cs)'s `SendCommandAsync` is used. In the scenario definition, [ScenarioHelpers](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTestApp/ScenarioHelpers.cs)'s `WaitForCommandAsync` is used. This can be used to synchronize various points of the test application with the execution of the dotnet-monitor Api from the test itself.
## Native/Profiler Tests
-- [Microsoft.Diagnostics.Monitoring.Profiler.UnitTests](../../src/Tests/Microsoft.Diagnostics.Monitoring.Profiler.UnitTests/)
-- [Microsoft.Diagnostics.Monitoring.Profiler.UnitTestApp](../../src/Tests/Microsoft.Diagnostics.Monitoring.Profiler.UnitTestApp/)
+- [Microsoft.Diagnostics.Monitoring.Profiler.UnitTests](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.Profiler.UnitTests/)
+- [Microsoft.Diagnostics.Monitoring.Profiler.UnitTestApp](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.Profiler.UnitTestApp/)
This test assembly provides a test to make sure the dotnet-monitor profiler can load into a target app.
## Schema Generation
-- [Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests](../../src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests/)
-- [Microsoft.Diagnostics.Monitoring.ConfigurationSchema](../../src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema/)
-- [Microsoft.Diagnostics.Monitoring.Options](../../src/Microsoft.Diagnostics.Monitoring.Options)
+- [Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests/)
+- [Microsoft.Diagnostics.Monitoring.ConfigurationSchema](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema/)
+- [Microsoft.Diagnostics.Monitoring.Options](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Microsoft.Diagnostics.Monitoring.Options)
-Dotnet-monitor generates [schema.json](../../documentation/schema.json) using unit tests. If dotnet-monitor's configuration changes, the schema.json file needs to be updated.
-Note that it is possible to compile option classes directly into the `ConfigurationSchema` project. This may be necessary in order to attribute properties appropriately for schema generation. See [Microsoft.Diagnostics.Monitoring.ConfigurationSchema.csproj](../../src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.csproj). See the [Configuration](./configuration.md#how-configuration-works) learning path for more details.
+Dotnet-monitor generates [schema.json](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/documentation/schema.json) using unit tests. If dotnet-monitor's configuration changes, the schema.json file needs to be updated.
+Note that it is possible to compile option classes directly into the `ConfigurationSchema` project. This may be necessary in order to attribute properties appropriately for schema generation. See [Microsoft.Diagnostics.Monitoring.ConfigurationSchema.csproj](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.csproj). See the [Configuration](./configuration.md#how-configuration-works) learning path for more details.
## OpenAPI generation
-- [Microsoft.Diagnostics.Monitoring.OpenApiGen.UnitTests](../../src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen.UnitTests/)
-- [Microsoft.Diagnostics.Monitoring.OpenApiGen](../../src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/)
+- [Microsoft.Diagnostics.Monitoring.OpenApiGen.UnitTests](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen.UnitTests/)
+- [Microsoft.Diagnostics.Monitoring.OpenApiGen](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/)
-These assemblies and tests are used to generate the [OpenAPI spec](../../documentation/openapi.json) for the dotnet-monitor API. Changes to the dotnet-monitor api surface require updating `openapi.json`.
+These assemblies and tests are used to generate the [OpenAPI spec](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/documentation/openapi.json) for the dotnet-monitor API. Changes to the dotnet-monitor api surface require updating `openapi.json`.
If using VSCode or Codespaces, you can also use the `Regenerate openapi.json` task.
## Startup hooks / hosting startup
-- [Microsoft.Diagnostics.Monitoring.Tool.TestStartupHook](../../src/Tests/Microsoft.Diagnostics.Monitoring.Tool.TestStartupHook/)
+- [Microsoft.Diagnostics.Monitoring.Tool.TestStartupHook](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.TestStartupHook/)
This assembly is injected into a dotnet-monitor runner (using `DOTNET_STARTUP_HOOKS`) to facilitate Assembly resolution during test runs.
-- [Microsoft.Diagnostics.Monitoring.Tool.TestHostingStartup](../../src/Tests/Microsoft.Diagnostics.Monitoring.Tool.TestHostingStartup/)
+- [Microsoft.Diagnostics.Monitoring.Tool.TestHostingStartup](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.TestHostingStartup/)
Uses `ASPNETCORE_HOSTINGSTARTUPASSEMBLIES` to inject a service into dotnet-monitor during test time. This allows tests to locate files that are not normally part of the test deployment,
such as the native profiler.
-- [Microsoft.Diagnostics.Monitoring.StartupHook.UnitTests](../../src/Tests/Microsoft.Diagnostics.Monitoring.StartupHook.UnitTests/)
+- [Microsoft.Diagnostics.Monitoring.StartupHook.UnitTests](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.StartupHook.UnitTests/)
Unit tests around features that are injected via `DOTNET_STARTUP_HOOKS` into the target application. This currently includes the Exceptions History feature.
## Misc test assemblies
-- [Microsoft.Diagnostics.Monitoring.TestCommon](../../src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/)
+- [Microsoft.Diagnostics.Monitoring.TestCommon](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/)
Utility classes that are shared between Unit Tests and Functional Tests.
-- [Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon](../../src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/)
+- [Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon](https://github.com/dotnet/dotnet-monitor/blob/341ff64a6097fe0bc66950e254e6160abcf77b84/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/)
Utility classes shared between unit test assemblies.