diff --git a/.github/workflows/powershell.yml b/.github/workflows/powershell.yml index 21178a1..88e9308 100644 --- a/.github/workflows/powershell.yml +++ b/.github/workflows/powershell.yml @@ -7,6 +7,7 @@ on: - 'docs/**' - 'Changelog.md' - 'README.md' + - src/internal/Export-HelpToMd.ps1 pull_request: branches: [ "main" ] @@ -70,7 +71,7 @@ jobs: image: mcr.microsoft.com/powershell:${{ matrix.pwshv }}-ubuntu-22.04 strategy: matrix: - pwshv: ['7.3','7.4'] + pwshv: ['7.4','preview-7.5'] steps: - uses: actions/checkout@v4 diff --git a/build.ps1 b/build.ps1 index 96c4cfa..5bdc003 100644 --- a/build.ps1 +++ b/build.ps1 @@ -35,11 +35,12 @@ if ( (Get-Command 'nbgv' -CommandType Application -ErrorAction SilentlyContinue) if (!$PSBoundParameters.ContainsKey('Revision')) { $Revision = $(nbgv get-version -v VersionRevision) } } +$module = 'potel' $parent = $PSScriptRoot $parent = [string]::IsNullOrEmpty($parent) ? $pwd.Path : $parent $src = Join-Path $parent -ChildPath "src" $docs = Join-Path $parent -ChildPath "docs" -$publish = Join-Path $parent -ChildPath "publish" -AdditionalChildPath 'potel' +$publish = [System.IO.Path]::Combine($parent, "publish", $module) $csproj = Join-Path -Path $src -ChildPath "dotnet" -AdditionalChildPath "potel.csproj" $bin = Join-Path -Path $src -ChildPath "dotnet" -AdditionalChildPath "bin" $obj = Join-Path -Path $src -ChildPath "dotnet" -AdditionalChildPath "obj" @@ -55,19 +56,20 @@ Write-Host "dotnet: $([Environment]::Version)" Write-Host "ps: $($PSVersionTable.PSVersion)" $manifest = @{ - Path = Join-Path -Path $publish -ChildPath 'potel.psd1' + Path = Join-Path -Path $publish -ChildPath "$module.psd1" Author = 'Chris Hunt' CompanyName = 'Chris Hunt' - Copyright = 'Chris Hunt' + Copyright = '(c) Chris Hunt. All rights reserved.' CompatiblePSEditions = "Core" Description = 'PowerShell module for collecting and sending Open Telemetry' - LicenseUri = 'https://github.com/cdhunt/potel/blob/main/LICENSE' + GUID = '0be70178-3d95-45cd-b3c5-d024ba8c18c7' + LicenseUri = "https://github.com/cdhunt/$module/blob/main/LICENSE" FunctionsToExport = @() ModuleVersion = [version]::new($Major, $Minor, $Build, $Revision) ProcessorArchitecture = 'Amd64' - PowerShellVersion = '7.3' - ProjectUri = 'https://github.com/cdhunt/potel' - RootModule = 'potel.psm1' + PowerShellVersion = '7.4' + ProjectUri = "https://github.com/cdhunt/$module" + RootModule = "$module.psm1" Tags = @('otel', 'distributed-tracing', 'metrics', 'telemetry', 'diagnostics') } @@ -94,7 +96,7 @@ function Build { Get-ChildItem -Path $_ -filter "potel.dll" | Remove-Item -Force -ErrorAction SilentlyContinue } - Copy-Item -Path "$src/potel.psm1" -Destination $publish + Copy-Item -Path "$src/$module.psm1" -Destination $publish Copy-Item -Path @("$parent/LICENSE", "$parent/README.md") -Destination $publish $internalFunctions = Get-ChildItem -Path "$src/internal/*.ps1" @@ -129,11 +131,20 @@ function Build { function Test { param () - if ($null -eq (Get-Module Pester -ListAvailable)) { - Install-Module -Name Pester -Confirm:$false -Force + if ($null -eq (Get-Module Pester -ListAvailable | Where-Object { [version]$_.Version -ge [version]"5.5.0" })) { + Install-Module -Name Pester -MinimumVersion 5.5.0 -Confirm:$false -Force } - Invoke-Pester -Path test + $config = New-PesterConfiguration -Hashtable @{ + Run = @{ Path = "test" } + TestResult = @{ + Enabled = $true + OutputFormat = "NUnitXml" + } + Output = @{ Verbosity = "Detailed" } + } + + Invoke-Pester -Configuration $config } function ChangeLog { @@ -181,24 +192,28 @@ function Publish { function Docs { param () + if ($null -eq (Get-Module Build-Docs -ListAvailable | Where-Object { [version]$_.Version -ge [version]"0.2.0.2" })) { + Install-Module -Name Build-Docs -MinimumVersion 0.2.0.2 -Confirm:$false -Force + } + Import-Module $publish -Force - $commands = Get-Command -Module potel - $HelpToMd = Join-Path -Path $src -ChildPath 'internal' -AdditionalChildPath 'Export-HelpToMd.ps1' - . $HelpToMd + $help = Get-HelpModuleData $module - @('# Potel', [System.Environment]::NewLine) | Set-Content -Path "$docs/README.md" - $($manifest.Description) | Add-Content -Path "$docs/README.md" - @('## Cmdlets', [System.Environment]::NewLine) | Add-Content -Path "$docs/README.md" + # docs/README.md + $help | New-HelpDoc | + Add-ModuleProperty Name -H1 | + Add-ModuleProperty Description | + Add-HelpDocText "Commands" -H2 | + Add-ModuleCommand -AsLinks | + Out-HelpDoc -Path 'docs/README.md' - foreach ($command in $Commands | Sort-Object -Property Verb) { + # Individual Commands + foreach ($command in $help.Commands) { $name = $command.Name - $docPath = Join-Path -Path $docs -ChildPath "$name.md" - $help = Get-Help -Name $name - - Export-HelpToMd $help | Set-Content -Path $docPath - - "- [$name]($name.md) $($help.Synopsis)" | Add-Content -Path "$docs/README.md" + $doc = New-HelpDoc -HelpModuleData $help + $doc.Text = $command.ToMD() + $doc | Out-HelpDoc -Path "docs/$name.md" } ChangeLog | Set-Content -Path "$parent/Changelog.md" diff --git a/docs/Add-ActivityEvent.md b/docs/Add-ActivityEvent.md new file mode 100644 index 0000000..30b0623 --- /dev/null +++ b/docs/Add-ActivityEvent.md @@ -0,0 +1,18 @@ +# Add-ActivityEvent + +Add a timestamped message to an Activity. + +## Parameters + +### Parameter Set 1 + +- `[String]` **Message** _The message string for the ActivityEvent._ Mandatory +- `[Activity]` **Activity** _An instance of an Activity._ Mandatory, ValueFromPipeline + +## Links + +- [Start-Activity](Start-Activity.md) + +## Notes + +Events are timestamped messages that can attach an arbitrary stream of additional diagnostic data to Activities. diff --git a/docs/Add-ActivityTag.md b/docs/Add-ActivityTag.md new file mode 100644 index 0000000..90eb7ca --- /dev/null +++ b/docs/Add-ActivityTag.md @@ -0,0 +1,18 @@ +# Add-ActivityTag + +Add key-value data called Tags to an Activity. + +## Parameters + +### Parameter Set 1 + +- `[Hashtable]` **Tags** _A collection of key/value pairs._ Mandatory +- `[Activity]` **Activity** _An instance of an Activity._ Mandatory, ValueFromPipeline + +## Links + +- [Start-Activity](Start-Activity.md) + +## Notes + +Commonly used to store any parameters of the work that may be useful for diagnostics diff --git a/docs/Add-ExporterConsole.md b/docs/Add-ExporterConsole.md index fc0ca55..a1b9cda 100644 --- a/docs/Add-ExporterConsole.md +++ b/docs/Add-ExporterConsole.md @@ -1,38 +1,32 @@ # Add-ExporterConsole - Adds OpenTelemetry.Exporter.Console -## Parameters +## Parameters ### Parameter Set 1 - -- `[TracerProviderBuilderBase]` **TracerProvider** _Instance of TracerProviderBuilderBase._. Mandatory, ValueFromPipeline - +- `[TracerProviderBuilderBase]` **TracerProvider** _Instance of TracerProviderBuilderBase._ Mandatory, ValueFromPipeline ### Parameter Set 2 - -- `[MeterProviderBuilderBase]` **MeterBuilder** _Instance of MeterProviderBuilderBase._. Mandatory, ValueFromPipeline - +- `[MeterProviderBuilderBase]` **MeterBuilder** _Instance of MeterProviderBuilderBase._ Mandatory, ValueFromPipeline ## Examples - ### Example 1 - ```powershell New-TracerProviderBuilder | Add-HttpClientInstrumentation | Add-ExporterConsole | Start-Trace ``` - ## Links - -- [New-TracerBuilder](New-TracerBuilder.md) - [Add-HttpClientInstrumentation](Add-HttpClientInstrumentation.md) - [Start-Tracer](Start-Tracer.md) + +## Outputs + +- `TracerProviderBuilderBase` diff --git a/docs/Add-ExporterOtlpTrace.md b/docs/Add-ExporterOtlpTrace.md index 7847978..ff589ca 100644 --- a/docs/Add-ExporterOtlpTrace.md +++ b/docs/Add-ExporterOtlpTrace.md @@ -1,70 +1,57 @@ # Add-ExporterOtlpTrace - Adds OpenTelemetry.Exporter.Console -## Parameters +## Parameters ### Parameter Set 1 - -- `[TracerProviderBuilderBase]` **TracerProvider** _Instance of TracerProviderBuilderBase._. Mandatory, ValueFromPipeline -- `[String]` **Endpoint** _OTLP endpoint address_. Mandatory -- `[Hashtable]` **Headers** _Headers to send_. -- `[UInt32]` **Timeout** _Send timeout in ms_. -- `[String]` **Protocol** _'grpc' or 'http/protobuf'_. - +- `[TracerProviderBuilderBase]` **TracerProvider** _Instance of TracerProviderBuilderBase._ Mandatory, ValueFromPipeline +- `[String]` **Endpoint** _OTLP endpoint address_ Mandatory +- `[Hashtable]` **Headers** _Headers to send_ +- `[UInt32]` **Timeout** _Send timeout in ms_ +- `[String]` **Protocol** _'grpc' or 'http/protobuf'_ ### Parameter Set 2 - -- `[MeterProviderBuilderBase]` **MeterBuilder** _Instance of MeterProviderBuilderBase._. Mandatory, ValueFromPipeline -- `[String]` **Endpoint** _OTLP endpoint address_. Mandatory -- `[Hashtable]` **Headers** _Headers to send_. -- `[UInt32]` **Timeout** _Send timeout in ms_. -- `[String]` **Protocol** _'grpc' or 'http/protobuf'_. - +- `[MeterProviderBuilderBase]` **MeterBuilder** _Instance of MeterProviderBuilderBase._ Mandatory, ValueFromPipeline +- `[String]` **Endpoint** _OTLP endpoint address_ Mandatory +- `[Hashtable]` **Headers** _Headers to send_ +- `[UInt32]` **Timeout** _Send timeout in ms_ +- `[String]` **Protocol** _'grpc' or 'http/protobuf'_ ## Examples - ### Example 1 - ```powershell New-TracerProviderBuilder | Add-HttpClientInstrumentation | Add-ExporterOtlpTrace -Endpoint http://localhost:9999 | Start-Trace ``` - - ### Example 2 - Configure the Otlp Exporter for Honeycomb. - ```powershell Add-ExporterOtlpTrace https://api.honeycomb.io:443 -Headers @{'x-honeycomb-team'='token'} ``` - - ### Example 3 - Configure the Otlp Exporter for Dynatrace. - ```powershell Add-ExporterOtlpTrace -Endpoint https://{your-environment-id}.live.dynatrace.com/api/v2/otlp -Headers @{'Authorization'='Api-Token dt.....'} -Protocol 'http/protobuf' ``` - ## Links - - [New-TracerProviderBuilder](New-TracerProviderBuilder.md) - [Add-HttpClientInstrumentation](Add-HttpClientInstrumentation.md) - [Start-Tracer](Start-Tracer.md) - [https://docs.honeycomb.io/getting-data-in/opentelemetry-overview/#using-the-honeycomb-opentelemetry-endpoint](https://docs.honeycomb.io/getting-data-in/opentelemetry-overview/#using-the-honeycomb-opentelemetry-endpoint) - [https://docs.dynatrace.com/docs/extend-dynatrace/opentelemetry/getting-started/otlp-export](https://docs.dynatrace.com/docs/extend-dynatrace/opentelemetry/getting-started/otlp-export) + +## Outputs + +- `TracerProviderBuilderBase` diff --git a/docs/Add-HttpClientInstrumentation.md b/docs/Add-HttpClientInstrumentation.md index 0684f0c..d7ae5b5 100644 --- a/docs/Add-HttpClientInstrumentation.md +++ b/docs/Add-HttpClientInstrumentation.md @@ -1,30 +1,28 @@ # Add-HttpClientInstrumentation - Adds Http Client Instrumentation -## Parameters +## Parameters ### Parameter Set 1 - -- `[TracerProviderBuilderBase]` **TracerProvider** _Instance of TracerProviderBuilderBase._. Mandatory, ValueFromPipeline - +- `[TracerProviderBuilderBase]` **TracerProvider** _Instance of TracerProviderBuilderBase._ Mandatory, ValueFromPipeline ## Examples - ### Example 1 - ```powershell New-TracerProviderBuilder | Add-HttpClientInstrumentation ``` - ## Links - - [New-TracerProviderBuilder](New-TracerProviderBuilder.md) +- [https://github.com/open-telemetry/opentelemetry-dotnet-contrib/blob/main/src/OpenTelemetry.Instrumentation.Http/README.md](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/blob/main/src/OpenTelemetry.Instrumentation.Http/README.md) + +## Outputs + +- `TracerProviderBuilderBase` diff --git a/docs/Add-ResourceConfiguration.md b/docs/Add-ResourceConfiguration.md index 79b522b..90378fd 100644 --- a/docs/Add-ResourceConfiguration.md +++ b/docs/Add-ResourceConfiguration.md @@ -1,40 +1,35 @@ # Add-ResourceConfiguration - Adds a Resource Configuration to a Tracer. A resource represents the entity producing telemetry as resource attributes. -## Parameters +## Parameters ### Parameter Set 1 - -- `[String]` **ServiceName** _An identifier usually base off of the name of the Service or Application generating the traces._. Mandatory -- `[Hashtable]` **Attribute** _A key-value pair. Used across telemetry signals - e.g. in Traces to attach data to an Activity (Span)_. Mandatory -- `[TracerProviderBuilderBase]` **TracerProvider** _A TracerProviderBuilderBase object_. Mandatory, ValueFromPipeline - +- `[String]` **ServiceName** _An identifier usually base off of the name of the Service or Application generating the traces._ Mandatory +- `[Hashtable]` **Attribute** _A key-value pair. Used across telemetry signals - e.g. in Traces to attach data to an Activity (Span)_ Mandatory +- `[TracerProviderBuilderBase]` **TracerProvider** _A TracerProviderBuilderBase object_ Mandatory, ValueFromPipeline ### Parameter Set 2 - -- `[String]` **ServiceName** _An identifier usually base off of the name of the Service or Application generating the traces._. Mandatory -- `[Hashtable]` **Attribute** _A key-value pair. Used across telemetry signals - e.g. in Traces to attach data to an Activity (Span)_. Mandatory -- `[MeterProviderBuilderBase]` **MeterBuilder** _Instance of MeterProviderBuilderBase_. Mandatory, ValueFromPipeline - +- `[String]` **ServiceName** _An identifier usually base off of the name of the Service or Application generating the traces._ Mandatory +- `[Hashtable]` **Attribute** _A key-value pair. Used across telemetry signals - e.g. in Traces to attach data to an Activity (Span)_ Mandatory +- `[MeterProviderBuilderBase]` **MeterBuilder** _Instance of MeterProviderBuilderBase_ Mandatory, ValueFromPipeline ## Examples - ### Example 1 - ```powershell New-TracerProviderBuilder | Add-HttpClientInstrumentation | Add-ResourceConfiguration -ServiceName $ExecutionContext.Host.Name -Attribute @{"host.name" = $(hostname)} | Add-ExporterConsole | Start-Tracer ``` - ## Links - - [https://opentelemetry.io/docs/instrumentation/net/resources/](https://opentelemetry.io/docs/instrumentation/net/resources/) + +## Outputs + +- `TracerProviderBuilderBase` diff --git a/docs/Add-TracerSource.md b/docs/Add-TracerSource.md index 0839ce9..920d011 100644 --- a/docs/Add-TracerSource.md +++ b/docs/Add-TracerSource.md @@ -1,53 +1,43 @@ # Add-TracerSource - Adds and ActivitySource to a TracerProviderBuilder -## Parameters +## Parameters ### Parameter Set 1 - -- `[String[]]` **Name** _Name of the Activity_. Mandatory -- `[TracerProviderBuilderBase]` **TracerProviderBuilder** _A TracerProviderBuilderBase object_. Mandatory, ValueFromPipeline - +- `[String[]]` **Name** _Name of the Activity_ Mandatory +- `[TracerProviderBuilderBase]` **TracerProviderBuilder** _A TracerProviderBuilderBase object_ Mandatory, ValueFromPipeline ### Parameter Set 2 - -- `[ActivitySource]` **ActivitySource** _An ActivitySource object_. Mandatory -- `[TracerProviderBuilderBase]` **TracerProviderBuilder** _A TracerProviderBuilderBase object_. Mandatory, ValueFromPipeline - +- `[ActivitySource]` **ActivitySource** _An ActivitySource object_ Mandatory +- `[TracerProviderBuilderBase]` **TracerProviderBuilder** _A TracerProviderBuilderBase object_ Mandatory, ValueFromPipeline ## Examples - ### Example 1 - Add a source by Name. - ```powershell New-TracerProviderBuilder | Add-TracerSource -Name "MyActivity" ``` - - ### Example 2 - Create an Activity Soruce object. - ```powershell $source = New-ActivitySource -Name "MyActivity" New-TracerProviderBuilder | Add-TracerSource -AcvititySource $source ``` - ## Links - - [New-TracerProviderBuilder](New-TracerProviderBuilder.md) - [New-ActivitySource](New-ActivitySource.md) - [https://opentelemetry.io/docs/instrumentation/net/manual/#setting-up-an-activitysource](https://opentelemetry.io/docs/instrumentation/net/manual/#setting-up-an-activitysource) + +## Outputs + +- `TracerProviderBuilderBase` diff --git a/docs/Disable-OtelDiagnosticLog.md b/docs/Disable-OtelDiagnosticLog.md new file mode 100644 index 0000000..e8d43d7 --- /dev/null +++ b/docs/Disable-OtelDiagnosticLog.md @@ -0,0 +1,20 @@ +# Disable-OtelDiagnosticLog + +Remove the `OTEL_DIAGNOSTICS.json` file to disabled the internal logs generated by all OpenTelemetry components. + +## Parameters + + +## Examples + +### Example 1 + +Disable the internal logs. + +```powershell +Disable-OtelDiagnosticLog +``` + +## Links + +- [Enable-OtelDiagnosticLog](Enable-OtelDiagnosticLog.md) diff --git a/docs/Enable-OtelDiagnosticLog.md b/docs/Enable-OtelDiagnosticLog.md new file mode 100644 index 0000000..f648008 --- /dev/null +++ b/docs/Enable-OtelDiagnosticLog.md @@ -0,0 +1,40 @@ +# Enable-OtelDiagnosticLog + +Create the `OTEL_DIAGNOSTICS.json` file to enable the internal logs generated by all OpenTelemetry components. + +## Parameters + +### Parameter Set 1 + +- `[String]` **LogDirectory** _The directory where the output log file will be stored. It can be an absolute path or a relative path to the current directory. Default is current directory._ +- `[Int32]` **FileSize** _Specifies the log file size in KiB. The log file will never exceed this configured size, and will be overwritten in a circular way. Default is `32768`._ +- `[Diagnostics.Tracing.EventLevel]` **LogLevel** _The lowest level of the events to be captured. Default is `Warning`._ + +## Examples + +### Example 1 + +Write an Otel Diagnostic log to C:\logs. + +```powershell +Enable-OtelDiagnosticLog -LogDirectory C:\logs +``` + +### Example 2 + +Includes the Error and Critical levels. + +```powershell +Enable-OtelDiagnosticLog -LogLevel Warning +``` + +## Links + +- [Disable-OtelDiagnosticLog](Disable-OtelDiagnosticLog.md) +- [https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/src/OpenTelemetry#self-diagnostics](https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/src/OpenTelemetry#self-diagnostics) + +## Notes + +The self-diagnostics feature can be enabled/changed/disabled while the process is running (without restarting the process). The SDK will attempt to read the configuration file every 10 seconds in non-exclusive read-only mode. The SDK will create or overwrite a file with new logs according to the configuration. This file will not exceed the configured max size and will be overwritten in a circular way. + +A log file named as `ExecutableName.ProcessId.log` (e.g. pwsh.exe.12345.log) will be generated at the specified directory LogDirectory, into which logs are written to. diff --git a/docs/Get-OtelDiagnosticLog.md b/docs/Get-OtelDiagnosticLog.md new file mode 100644 index 0000000..96d2427 --- /dev/null +++ b/docs/Get-OtelDiagnosticLog.md @@ -0,0 +1,20 @@ +# Get-OtelDiagnosticLog + +Read the contents of the file ExecutableName.ProcessId.log from the path specified with Enable-OtelDiagnosticLog. + +## Parameters + + +## Examples + +### Example 1 + +Get the internal logs. + +```powershell +Get-OtelDiagnosticLog +``` + +## Links + +- [Enable-OtelDiagnosticLog](Enable-OtelDiagnosticLog.md) diff --git a/docs/New-ActivitySource.md b/docs/New-ActivitySource.md index 545e6ce..6c12436 100644 --- a/docs/New-ActivitySource.md +++ b/docs/New-ActivitySource.md @@ -1,14 +1,23 @@ # New-ActivitySource +Create an instance of ActivitySource. ActivitySource provides APIs to create and start Activity objects. -Create a new ActivitySource object ## Parameters - ### Parameter Set 1 +- `[String]` **Name** _The Source Name. The source name passed to the constructor has to be unique to avoid the conflicts with any other sources._ Mandatory +- `[String]` **Version** _The version parameter is optional._ + +## Links + +- [Start-Activity](Start-Activity.md) +- [https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs#activitysource](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs#activitysource) + +## Notes -- `[String]` **Name** _Parameter help description_. Mandatory +ActivitySource is the .Net implementation of an OpenTelemetry "Tracer" +## Outputs -## Examples +- `System.Diagnostics.ActivitySource` diff --git a/docs/New-TracerProviderBuilder.md b/docs/New-TracerProviderBuilder.md index 841198c..464959e 100644 --- a/docs/New-TracerProviderBuilder.md +++ b/docs/New-TracerProviderBuilder.md @@ -1,49 +1,41 @@ # New-TracerProviderBuilder - Creates instance of OpenTelemetry.Sdk TracerProviderBuilder -## Parameters +## Parameters ### Parameter Set 1 - -- `[String]` **ActivityName** _Parameter help description_. - +- `[String]` **ActivityName** _Parameter help description_ ### Parameter Set 2 - -- `[ActivitySource]` **ActivitySource** _Parameter help description_. - +- `[ActivitySource]` **ActivitySource** _Parameter help description_ ## Examples - ### Example 1 - ```powershell New-TracerProviderBuilder ``` - - ### Example 2 - ```powershell New-TracerProviderBuilder -ActivyName "MyActivity" ``` - ## Links - +- [https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry/Sdk.cs](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry/Sdk.cs) - [Add-TracerSource](Add-TracerSource.md) - [Start-Tracer](Start-Tracer.md) - [Stop-Tracer](Stop-Tracer.md) -- [https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry/Sdk.cs](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry/Sdk.cs) + +## Outputs + +- `TracerProviderBuilder` diff --git a/docs/README.md b/docs/README.md index d6f857e..9a30a89 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,16 +1,23 @@ -# Potel - +# potel PowerShell module for collecting and sending Open Telemetry -## Cmdlets +## Commands + +- [Add-ActivityEvent](Add-ActivityEvent.md) _Add a timestamped message to an Activity._ +- [Add-ActivityTag](Add-ActivityTag.md) _Add key-value data called Tags to an Activity._ +- [Add-ExporterConsole](Add-ExporterConsole.md) _Adds a Console Exporter_ +- [Add-ExporterOtlpTrace](Add-ExporterOtlpTrace.md) _Adds an OTLP Exporter_ +- [Add-HttpClientInstrumentation](Add-HttpClientInstrumentation.md) _Adds Http Client Instrumentation_ +- [Add-ResourceConfiguration](Add-ResourceConfiguration.md) _Adds a Resource Configuration to a Tracer_ +- [Add-TracerSource](Add-TracerSource.md) _Adds and ActivitySource to a TracerProviderBuilder_ +- [Disable-OtelDiagnosticLog](Disable-OtelDiagnosticLog.md) _Disable the internal logs generated by all OpenTelemetry components._ +- [Enable-OtelDiagnosticLog](Enable-OtelDiagnosticLog.md) _Enable the internal logs generated by all OpenTelemetry components._ +- [Get-OtelDiagnosticLog](Get-OtelDiagnosticLog.md) _Get the contents of the diagnostic log._ +- [New-ActivitySource](New-ActivitySource.md) _Create an instance of ActivitySource._ +- [New-TracerProviderBuilder](New-TracerProviderBuilder.md) _Creates new Tracer Provider Builder_ +- [Set-ActivityStatus](Set-ActivityStatus.md) _Set the Activity Status._ +- [Start-Activity](Start-Activity.md) _Start an Activity._ +- [Start-Tracer](Start-Tracer.md) _Start the Tracer_ +- [Stop-Tracer](Stop-Tracer.md) _Stop the Tracer_ -- [Add-ExporterConsole](Add-ExporterConsole.md) Adds a Console Exporter -- [Add-ExporterOtlpTrace](Add-ExporterOtlpTrace.md) Adds an OTLP Exporter -- [Add-HttpClientInstrumentation](Add-HttpClientInstrumentation.md) Adds Http Client Instrumentation -- [Add-ResourceConfiguration](Add-ResourceConfiguration.md) Adds a Resource Configuration to a Tracer -- [Add-TracerSource](Add-TracerSource.md) Adds and ActivitySource to a TracerProviderBuilder -- [New-ActivitySource](New-ActivitySource.md) Create a new ActivitySource object -- [New-TracerProviderBuilder](New-TracerProviderBuilder.md) Creates new Tracer Provider Builder -- [Start-Tracer](Start-Tracer.md) Start the Tracer -- [Stop-Tracer](Stop-Tracer.md) Stop the Tracer diff --git a/docs/Set-ActivityStatus.md b/docs/Set-ActivityStatus.md new file mode 100644 index 0000000..ae80e0e --- /dev/null +++ b/docs/Set-ActivityStatus.md @@ -0,0 +1,22 @@ +# Set-ActivityStatus + +OpenTelemetry allows each Activity to report a Status that represents the pass/fail result of the work. + +## Parameters + +### Parameter Set 1 + +- `[Switch]` **StatusCode** _An ActivityStatusCode. The ActivityStatusCode values are represented as either, `Unset`, `Ok`, and `Error`._ Mandatory +- `[String]` **Description** _Optional Description that provides a descriptive message of the Status. `Description` **MUST** only be used with the `Error` `StatusCode` value._ +- `[Activity]` **Activity** _Parameter help description_ Mandatory, ValueFromPipeline + +## Links + +- [Start-Activity](Start-Activity.md) + +## Notes + +StatusCode is one of the following values: +- Unset: The default status. +- Ok: The operation has been validated by an Application developer or Operator to have completed successfully. +- Error: The operation contains an error. diff --git a/docs/Start-Activity.md b/docs/Start-Activity.md new file mode 100644 index 0000000..a1d1f71 --- /dev/null +++ b/docs/Start-Activity.md @@ -0,0 +1,32 @@ +# Start-Activity + +Start an Activity. + +## Parameters + +### Parameter Set 1 + +- `[String]` **Name** _The name of the activity._ Mandatory +- `[Switch]` **Kind** _An Activity.Kind for this Activity. + - Internal: Internal operation within an application, as opposed to operations with remote parents or children. This is the default value. + - Server: Requests incoming from external component + - Client: Outgoing request to the external component + - Producer: Output provided to external components + - Consumer: Output received from an external component_ +- `[ActivitySource]` **ActivitySource** _An ActivitySource._ Mandatory, ValueFromPipeline + +## Links + +- [New-ActivitySource](New-ActivitySource.md) +- [https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs) + +## Notes + +Activity is the .Net implementation of an OpenTelemetry "Span". +If there are no registered listeners or there are listeners that are not interested, Start-Activity +will return null and avoid creating the Activity object. This is a performance optimization so that +the code pattern can still be used in functions that are called frequently. + +## Outputs + +- `System.Diagnostics.Activity` diff --git a/docs/Start-Tracer.md b/docs/Start-Tracer.md index ee43b13..6406bf5 100644 --- a/docs/Start-Tracer.md +++ b/docs/Start-Tracer.md @@ -1,21 +1,14 @@ # Start-Tracer - Start the Tracer -## Parameters +## Parameters ### Parameter Set 1 - -- `[TracerProviderBuilderBase]` **TracerProviderBuilder** _A TracerProviderBuilderBase object_. Mandatory, ValueFromPipeline -- `[switch]` **PassThru** _Send the build TracerProvider to the pipeline_. - - -## Examples - +- `[TracerProviderBuilderBase]` **TracerProviderBuilder** _A TracerProviderBuilderBase object_ Mandatory, ValueFromPipeline +- `[Switch]` **PassThru** _Send the build TracerProvider to the pipeline_ ## Links - - [New-TracerProviderBuilder](New-TracerProviderBuilder.md) diff --git a/docs/Stop-Tracer.md b/docs/Stop-Tracer.md index 57ae20e..6481b64 100644 --- a/docs/Stop-Tracer.md +++ b/docs/Stop-Tracer.md @@ -1,14 +1,9 @@ # Stop-Tracer - Stop the Tracer -## Parameters +## Parameters ### Parameter Set 1 - -- `[TracerProvider]` **TracerProvider** _Parameter help description_. ValueFromPipeline - - -## Examples +- `[TracerProvider]` **TracerProvider** _Parameter help description_ ValueFromPipeline diff --git a/docs/images/dynatrace.png b/docs/images/dynatrace.png new file mode 100644 index 0000000..6e9f898 Binary files /dev/null and b/docs/images/dynatrace.png differ diff --git a/docs/images/honeycombtrace.png b/docs/images/honeycombtrace.png new file mode 100644 index 0000000..d7ba785 Binary files /dev/null and b/docs/images/honeycombtrace.png differ diff --git a/samples/README.md b/samples/README.md new file mode 100644 index 0000000..0fed129 --- /dev/null +++ b/samples/README.md @@ -0,0 +1,84 @@ +# Sample.psm1 + +This ia a overly simplified sample module used to explain some of the basic functionality of **potel**. + +This sample assume you have a local instance of Jaeger running to receive trace data. You can start up a server with the following Docker command. + +```powershell +docker run --rm --name jaeger ` + -p 16686:16686 ` + -p 4317:4317 ` + -p 4318:4318 ` + -p 5778:5778 ` + -p 9411:9411 ` + jaegertracing/jaeger:2.1.0 +``` + +## Terminology + +Here are some terms as documented at [opentelemetry.io/docs/concepts/signals/traces](https://opentelemetry.io/docs/concepts/signals/traces/) and [opentelemetry.io/docs/languages/net/instrumentation/#a-note-on-terminology](https://opentelemetry.io/docs/languages/net/instrumentation/#a-note-on-terminology). + +### Tracer + +A Tracer creates spans containing more information about what is happening for a given operation, such as a request in a service. Tracers are created from Tracer Providers. + +### Tracer Provider + +A Tracer Provider is a factory for Tracers. In most applications, a Tracer Provider is initialized once and its lifecycle matches the application's lifecycle. + +PowerShell modules and cmdlets don't seamlessly line up with the typical Tracer lifecycle. More on that later. + +### Activities (aka Spans) + +A span represents a unit of work or operation. Spans are the building blocks of Traces. + +### Activity Events (aka Span Events) + +An Activity Event can be thought of as a structured log message on an Activity, typically used to denote a meaningful, singular point in time during the Activity's duration. + +### Resources + +A Resource represents the entity producing telemetry as resource attributes. The `$env:OTEL_RESOURCE_ATTRIBUTES` environment variable can also be used to inject resources into your application. + +## How it works + +### Set up the Tracer + +The Sample module creates a Tracer in manifest using the Service Name `potel-sample`. The Service Name is the top most pieces of metadata and should not change if you want to compare traces across time. It also defines an Activity Source named `potel-sample`. The Activity Source and Service Name do not need to be the same. Along with the Service Name, we add a `host.name` Resource Attribute. You can find an Attribute Registry at [opentelemetry.io/docs/specs/semconv/attributes-registry](https://opentelemetry.io/docs/specs/semconv/attributes-registry/). + +We attach two Exporters - OtlpTrace and Console. All activities will be sent to both Exporters. The OtlpTrace exporter will send data to Jaeger in this instance and the Console exporter will write output to StdOut. + +This sample also uses the [Zero-code instrumentation](https://opentelemetry.io/docs/concepts/instrumentation/zero-code/) for `System.Net.Http.HttPClient` which will automatically create Activities when methods of `HttPClient` are invoked. + +The Tracer exists globally in the PowerShell session in the current version of **potel**. This brings with it some considerations. The `HttPClient` instrumentation will record every instance of `HttPClient` for any process within PowerShell. Filtering has not yet been implemented. It will also continue to generate new Activities/Spans until `Stop-Tracer` is called or the PowerShell process is stopped. + +```powershell +$activitySource = New-ActivitySource -Name potel-sample +New-TracerProviderBuilder | +Add-TracerSource -ActivitySource $activitySource | +Add-ResourceConfiguration -ServiceName potel-sample -Attribute @{"host.name" = 'chunt' } | +Add-HttpClientInstrumentation | +Add-ExporterOtlpTrace -Endpoint http://localhost:4317 | +Add-ExporterConsole | +Start-Tracer +``` + +### Record an Activity + +`Start-Activity` will create a new Activity instance from the given Activity Source. Remember that the Activity Source is what routes Activities to Tracers and the Exporters. + +```powershell +$activity = $activitySource | Start-Activity -Name "Get-SampleSomething" +``` + +If you create a new Activity while another Activity instance is still in scope you will create a nested Activity. + +### Example output + +Here is what the data in looks like in Jaeger when you import the module `sample.psm1` and invoke `Get-SampleSomething`. + +![](jaegersample.jpg) + +You see three nested spans: `Get-SampleSomething` calls `Get-Google` which makes an Http Get request to google.com. Within `Get-SampleSomething` you can see the two Events logged and all three spans include the resource attribute `host.name = chunt`. + +With HttpClientInstrumentation the Get request will include a standard `traceid` header and if that request hits a service that is also reporting Otel traces to the same Exporter you should be able to follow the Distributed Trace across multiple services. diff --git a/samples/jaegersample.jpg b/samples/jaegersample.jpg new file mode 100644 index 0000000..73be5f6 Binary files /dev/null and b/samples/jaegersample.jpg differ diff --git a/samples/sample.psm1 b/samples/sample.psm1 new file mode 100644 index 0000000..4b583ee --- /dev/null +++ b/samples/sample.psm1 @@ -0,0 +1,60 @@ +# The Activity Source binds Activities (Spans) to a Tracer. +$activitySource = New-ActivitySource -Name potel-sample + +# A Tracer provides the configuration and lifecycle of your instrumentation. +# The Tracer does nothing itself, but binds inputs and outputs. +New-TracerProviderBuilder | +Add-TracerSource -ActivitySource $activitySource | +Add-ResourceConfiguration -ServiceName potel-sample -Attribute @{"host.name" = $(hostname) } | +Add-HttpClientInstrumentation | +Add-ExporterOtlpTrace -Endpoint http://localhost:4317 | +Add-ExporterConsole | +Start-Tracer + +# Enabled the internal Otel SDK log +$diagConfig = Enable-OtelDiagnosticLog -LogLevel Warning + +function Get-SampleSomething { + [CmdletBinding()] + param ( + [Parameter(Position = 0)] + [int] + $SecondsToWait + ) + + # An Activity defines a unit of work and has a start and a stop. + # Each Activity is equivalent to an Otel Span. + $activity = $activitySource | Start-Activity -Name "Get-SampleSomething" + + # Activities have lots of available metadata you can use to enrich your spans. + $activity | Add-ActivityTag @{'SecondsToWait' = $SecondsToWait } + + # Activity Events are timestamped log entries within an Activity + $activity | Add-ActivityEvent -Message "About to go to sleep" + + Start-Sleep -Seconds $SecondsToWait + + $activity | Add-ActivityEvent -Message "Finished sleeping" + + Get-Google + + # You can explicitly stop an activity to capture accurate timing + $activity.Stop() +} + +function Get-Google { + [CmdletBinding()] + param ( + + ) + + # You can nest Activities. Since "Get-Google" Activity is started while the "Get-SampleSomething" Activity it will be a child of "Get-SampleSomething". + $activity = $activitySource | Start-Activity -Name "Get-Google" + + # Calls to methods that are part of HttpClient class will automatically create child spans because we included Add-HttpClientInstrumentation. + # https://github.com/open-telemetry/opentelemetry-dotnet-contrib/blob/main/src/OpenTelemetry.Instrumentation.Http/README.md + Invoke-WebRequest -Uri https://google.com | Out-Null + + $activity.Stop() + +} \ No newline at end of file diff --git a/src/dotnet/potel.csproj b/src/dotnet/potel.csproj index 4144847..9ed4377 100644 --- a/src/dotnet/potel.csproj +++ b/src/dotnet/potel.csproj @@ -7,11 +7,10 @@ - - - - - + + + + diff --git a/src/internal/Add-PackageTypes.ps1 b/src/internal/Add-PackageTypes.ps1 index 6b3d046..71825fa 100644 --- a/src/internal/Add-PackageTypes.ps1 +++ b/src/internal/Add-PackageTypes.ps1 @@ -20,7 +20,8 @@ function Add-PackageTypes { } process { - foreach ($path in (Get-ChildItem $target | Where-Object { $_.Name -like '*.dll' -and $_.BaseName -ne "grpc_csharp_ext.x64" } | Select-Object -ExpandProperty FullName)) { + $files = Get-ChildItem $target | Where-Object { $_.Name -like '*.dll' -and $_.BaseName -ne "grpc_csharp_ext.x64" -and $_.BaseName -ne 'Microsoft.Bcl.AsyncInterfaces' } | Select-Object -ExpandProperty FullName + foreach ($path in ($files)) { Add-Type -Path $path } } diff --git a/src/public/Add-ActivityEvent.ps1 b/src/public/Add-ActivityEvent.ps1 new file mode 100644 index 0000000..d8c1c95 --- /dev/null +++ b/src/public/Add-ActivityEvent.ps1 @@ -0,0 +1,31 @@ +<# +.SYNOPSIS + Add a timestamped message to an Activity. +.DESCRIPTION + Add a timestamped message to an Activity. +.PARAMETER Message + The message string for the ActivityEvent. +.PARAMETER Activity + An instance of an Activity. +.NOTES + Events are timestamped messages that can attach an arbitrary stream of additional diagnostic data to Activities. +.LINK + Start-Activity +#> +function Add-ActivityEvent { + [CmdletBinding()] + param ( + [Parameter(Mandatory, Position = 0)] + [string] + $Message, + + [Parameter(Mandatory, Position = 1, ValueFromPipeline)] + [System.Diagnostics.Activity] + $Activity + ) + + if ($null -ne $Activity) { + $activityEvent = [System.Diagnostics.ActivityEvent]::new($Message) + $Activity.AddEvent($activityEvent) + } +} \ No newline at end of file diff --git a/src/public/Add-ActivityTag.ps1 b/src/public/Add-ActivityTag.ps1 new file mode 100644 index 0000000..f700f0e --- /dev/null +++ b/src/public/Add-ActivityTag.ps1 @@ -0,0 +1,32 @@ +<# +.SYNOPSIS + Add key-value data called Tags to an Activity. +.DESCRIPTION + Add key-value data called Tags to an Activity. +.PARAMETER Tags + A collection of key/value pairs. +.PARAMETER Activity + An instance of an Activity. +.NOTES + Commonly used to store any parameters of the work that may be useful for diagnostics +.LINK + Start-Activity +#> +function Add-ActivityTag { + [CmdletBinding()] + param ( + [Parameter(Mandatory, Position = 0)] + [hashtable] + $Tags, + + [Parameter(Mandatory, Position = 1, ValueFromPipeline)] + [System.Diagnostics.Activity] + $Activity + ) + + if ($null -ne $Activity) { + foreach ($entry in $Tags.GetEnumerator()) { + $Activity.AddTag($entry.Key, $entry.Value) + } + } +} \ No newline at end of file diff --git a/src/public/Add-HttpClientInstrumentation.ps1 b/src/public/Add-HttpClientInstrumentation.ps1 index 6cc1e14..1b9c8e5 100644 --- a/src/public/Add-HttpClientInstrumentation.ps1 +++ b/src/public/Add-HttpClientInstrumentation.ps1 @@ -25,5 +25,5 @@ function Add-HttpClientInstrumentation { $type = [System.AppDomain]::CurrentDomain.GetAssemblies() | Where-Object Location -like "*potel*lib*OpenTelemetry.Instrumentation.Http.dll" | Select-Object -Last 1 - $type.GetType('OpenTelemetry.Trace.TracerProviderBuilderExtensions').GetMethod('AddHttpClientInstrumentation', ([System.Reflection.BindingFlags]::Public -bor [System.Reflection.BindingFlags]::Static), [OpenTelemetry.Trace.TracerProviderBuilder]).Invoke($null, @($TracerProvider)) + $type.GetType('OpenTelemetry.Trace.HttpClientInstrumentationTracerProviderBuilderExtensions').GetMethod('AddHttpClientInstrumentation', ([System.Reflection.BindingFlags]::Public -bor [System.Reflection.BindingFlags]::Static), [OpenTelemetry.Trace.TracerProviderBuilder]).Invoke($null, @($TracerProvider)) } \ No newline at end of file diff --git a/src/public/Disable-OtelDiagnosticLog.ps1 b/src/public/Disable-OtelDiagnosticLog.ps1 new file mode 100644 index 0000000..5370fea --- /dev/null +++ b/src/public/Disable-OtelDiagnosticLog.ps1 @@ -0,0 +1,33 @@ +<# +.SYNOPSIS + Disable the internal logs generated by all OpenTelemetry components. +.DESCRIPTION + Remove the `OTEL_DIAGNOSTICS.json` file to disabled the internal logs generated by all OpenTelemetry components. +.PARAMETER RemoveLog + +.LINK + Enable-OtelDiagnosticLog +.EXAMPLE + Disable-OtelDiagnosticLog + + Disable the internal logs. +#> +function Disable-OtelDiagnosticLog { + [CmdletBinding()] + param ( + [Parameter()] + [switch] + $RemoveLog + ) + + $name = 'OTEL_DIAGNOSTICS.json' + $path = Join-Path -Path ([System.IO.Directory]::GetCurrentDirectory()) -ChildPath $name + + Remove-Item -Path $path + + if ($RemoveLog) { + Write-Information "Sleeping for 10 seconds to allow SDK to reconfigure diagnostics." + Start-Sleep -Seconds 10 + Get-OtelDiagnosticLog | Remove-Item + } +} \ No newline at end of file diff --git a/src/public/Enable-OtelDiagnosticLog.ps1 b/src/public/Enable-OtelDiagnosticLog.ps1 new file mode 100644 index 0000000..a69c50d --- /dev/null +++ b/src/public/Enable-OtelDiagnosticLog.ps1 @@ -0,0 +1,63 @@ +<# +.SYNOPSIS + Enable the internal logs generated by all OpenTelemetry components. +.DESCRIPTION + Create the `OTEL_DIAGNOSTICS.json` file to enable the internal logs generated by all OpenTelemetry components. +.PARAMETER LogDirectory + The directory where the output log file will be stored. It can be an absolute path or a relative path to the current directory. Default is current directory. +.PARAMETER FileSize + Specifies the log file size in KiB. The log file will never exceed this configured size, and will be overwritten in a circular way. Default is `32768`. +.PARAMETER LogLevel + The lowest level of the events to be captured. Default is `Warning`. +.NOTES + The self-diagnostics feature can be enabled/changed/disabled while the process is running (without restarting the process). The SDK will attempt to read the configuration file every 10 seconds in non-exclusive read-only mode. The SDK will create or overwrite a file with new logs according to the configuration. This file will not exceed the configured max size and will be overwritten in a circular way. + + A log file named as `ExecutableName.ProcessId.log` (e.g. pwsh.exe.12345.log) will be generated at the specified directory LogDirectory, into which logs are written to. +.LINK + Get-OtelDiagnosticLog +.LINK + Disable-OtelDiagnosticLog +.LINK + https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/src/OpenTelemetry#self-diagnostics +.EXAMPLE + Enable-OtelDiagnosticLog -LogDirectory C:\logs + + Write an Otel Diagnostic log to C:\logs. +.EXAMPLE + Enable-OtelDiagnosticLog -LogLevel Warning + + Includes the Error and Critical levels. +#> +function Enable-OtelDiagnosticLog { + [CmdletBinding()] + param ( + [Parameter(Position = 0)] + [Alias("Path", "PSPath")] + [ValidateNotNullOrEmpty()] + [string] + $LogDirectory = '.', + + [Parameter(Position = 1)] + [ValidateRange(1024, 131072)] + [int] + $FileSize = 32768, + + [Parameter(Position = 2)] + [System.Diagnostics.Tracing.EventLevel] + $LogLevel = 'Warning' + ) + + $name = 'OTEL_DIAGNOSTICS.json' + $settings = [pscustomobject]@{ + LogDirectory = $LogDirectory + FileSize = $FileSize + LogLevel = $LogLevel.ToString() + } + $content = $settings | ConvertTo-Json + $path = Join-Path -Path ([System.IO.Directory]::GetCurrentDirectory()) -ChildPath $name + + $content | Set-Content -Path $path + + Get-Item $path + +} \ No newline at end of file diff --git a/src/public/Get-OtelDiagnosticLog.ps1 b/src/public/Get-OtelDiagnosticLog.ps1 new file mode 100644 index 0000000..ce9f024 --- /dev/null +++ b/src/public/Get-OtelDiagnosticLog.ps1 @@ -0,0 +1,39 @@ +<# +.SYNOPSIS + Get the contents of the diagnostic log. +.DESCRIPTION + Read the contents of the file ExecutableName.ProcessId.log from the path specified with Enable-OtelDiagnosticLog. +.LINK + Enable-OtelDiagnosticLog +.EXAMPLE + Get-OtelDiagnosticLog + Directory: C:\Users\user + Mode LastWriteTime Length Name + ---- ------------- ------ ---- + -a--- 12/23/2024 12:02 PM 33554432 pwsh.exe.131616.log + + Get the internal logs. +#> +function Get-OtelDiagnosticLog { + [CmdletBinding()] + param () + + $configName = 'OTEL_DIAGNOSTICS.json' + $configPath = Join-Path -Path ([System.IO.Directory]::GetCurrentDirectory()) -ChildPath $configName + + if (Test-Path -Path $configPath) { + $config = Get-Content -Path $configPath + $settings = $config | ConvertFrom-Json + + $executableName = Get-Process -Id $PID | Select-Object -ExpandProperty ProcessName + $logName = '{0}.exe.{1}.log' -f $executableName, $PID + + if ([IO.Path]::IsPathFullyQualified($settings.LogDirectory)) { + $logPath = Join-Path -Path $settings.LogDirectory -ChildPath $logName + } else { + $logPath = Join-Path -Path ([System.IO.Directory]::GetCurrentDirectory()) -ChildPath $settings.LogDirectory -AdditionalChildPath $logName + } + + Get-Item -Path $logPath + } +} \ No newline at end of file diff --git a/src/public/New-ActivitySource.ps1 b/src/public/New-ActivitySource.ps1 index 081a40d..01610df 100644 --- a/src/public/New-ActivitySource.ps1 +++ b/src/public/New-ActivitySource.ps1 @@ -1,15 +1,31 @@ <# .SYNOPSIS - Create a new ActivitySource object + Create an instance of ActivitySource. +.DESCRIPTION + Create an instance of ActivitySource. ActivitySource provides APIs to create and start Activity objects. +.PARAMETER Name + The Source Name. The source name passed to the constructor has to be unique to avoid the conflicts with any other sources. +.PARAMETER Version + The version parameter is optional. +.LINK + Start-Activity +.LINK + https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs#activitysource +.NOTES + ActivitySource is the .Net implementation of an OpenTelemetry "Tracer" #> function New-ActivitySource { [CmdletBinding()] + [OutputType('System.Diagnostics.ActivitySource')] param ( [Parameter(Mandatory, Position = 0)] [string] - $Name + $Name, + [Parameter(Position = 1)] + [string] + $Version = [string]::Empty ) - [System.Diagnostics.ActivitySource]::new($Name) + [System.Diagnostics.ActivitySource]::new($Name, $Version) } \ No newline at end of file diff --git a/src/public/Set-ActivityStatus.ps1 b/src/public/Set-ActivityStatus.ps1 new file mode 100644 index 0000000..d391838 --- /dev/null +++ b/src/public/Set-ActivityStatus.ps1 @@ -0,0 +1,43 @@ +<# +.SYNOPSIS + Set the Activity Status. +.DESCRIPTION + OpenTelemetry allows each Activity to report a Status that represents the pass/fail result of the work. +.PARAMETER StatusCode + An ActivityStatusCode. The ActivityStatusCode values are represented as either, `Unset`, `Ok`, and `Error`. +.PARAMETER Description + Optional Description that provides a descriptive message of the Status. `Description` **MUST** only be used with the `Error` `StatusCode` value. +.NOTES + StatusCode is one of the following values: + - Unset: The default status. + - Ok: The operation has been validated by an Application developer or Operator to have completed successfully. + - Error: The operation contains an error. +.LINK + Start-Activity +#> +function Set-ActivityStatus { + [CmdletBinding()] + param ( + # Parameter help description + [Parameter(Mandatory, Position = 0)] + [System.Diagnostics.ActivityStatusCode] + $StatusCode, + + [Parameter(Position = 1)] + [string] + $Description, + + [Parameter(Mandatory, Position = 2, ValueFromPipeline)] + [System.Diagnostics.Activity] + $Activity + ) + + if ($PSBoundParameters.ContainsKey('Description') -and $StatusCode -ne [System.Diagnostics.ActivityStatusCode]::Error ) { + $Description = $null + Write-Warning "Description MUST only be used with the Error StatusCode value." + } + + if ($null -ne $Activity) { + $Activity.SetStatus($StatusCode, $Description) + } +} \ No newline at end of file diff --git a/src/public/Start-Activity.ps1 b/src/public/Start-Activity.ps1 new file mode 100644 index 0000000..b0c31a0 --- /dev/null +++ b/src/public/Start-Activity.ps1 @@ -0,0 +1,43 @@ +<# +.SYNOPSIS + Start an Activity. +.PARAMETER Name + The name of the activity. +.PARAMETER Kind + An Activity.Kind for this Activity. + - Internal: Internal operation within an application, as opposed to operations with remote parents or children. This is the default value. + - Server: Requests incoming from external component + - Client: Outgoing request to the external component + - Producer: Output provided to external components + - Consumer: Output received from an external component +.PARAMETER ActivitySource + An ActivitySource. +.LINK + New-ActivitySource +.LINK + https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs +.NOTES + Activity is the .Net implementation of an OpenTelemetry "Span". + If there are no registered listeners or there are listeners that are not interested, Start-Activity + will return null and avoid creating the Activity object. This is a performance optimization so that + the code pattern can still be used in functions that are called frequently. +#> +function Start-Activity { + [CmdletBinding()] + [OutputType('System.Diagnostics.Activity')] + param ( + [Parameter(Mandatory, Position = 0)] + [string] + $Name, + + [Parameter(Position = 1)] + [System.Diagnostics.ActivityKind] + $Kind = [System.Diagnostics.ActivityKind]::Internal, + + [Parameter(Mandatory, Position = 2, ValueFromPipeline)] + [System.Diagnostics.ActivitySource] + $ActivitySource + ) + + $ActivitySource.StartActivity($Name, $Kind) +} \ No newline at end of file diff --git a/test/Tracer.Tests.ps1 b/test/Tracer.Tests.ps1 index bd18ebd..3572934 100644 --- a/test/Tracer.Tests.ps1 +++ b/test/Tracer.Tests.ps1 @@ -1,11 +1,5 @@ BeforeAll { - Import-Module $PSScriptRoot/../publish/potel -Force - $modulePath = Get-Module potel | Select-Object -ExpandProperty Path | Split-Path -Parent - - $addTypes = Join-Path -Path $modulePath -ChildPath internal -AdditionalChildPath Add-PackageTypes.ps1 - . "$addTypes" - - Add-PackageTypes -LibsDirectory "$modulePath/lib" + Import-Module $PSScriptRoot/../publish/potel/potel.psd1 -Force } Describe 'New-TracePRoviderBuilder' { @@ -147,6 +141,62 @@ Describe 'Add-ExporterOtlpTrace' { } } +Describe 'Enable-OtelDiagnosticLog' { + Context 'Create new config file with' { + BeforeAll { + Push-Location TestDrive:/ + $cwd = Get-PSDrive -Name TestDrive | Select-Object -ExpandProperty Root + [System.IO.Directory]::SetCurrentDirectory($cwd) + } + AfterAll { + Pop-Location + [System.IO.Directory]::SetCurrentDirectory($PWD.Path) + } + + It 'Should create "OTEL_DIAGNOSTICS.json"' { + $config = Enable-OtelDiagnosticLog + $config.FullName | Should -Exist + $config.FullName | Should -FileContentMatchMultiline '{\r?\n\s+"LogDirectory": "\.\",\r?\n\s+"FileSize": 32768,\r?\n\s+"LogLevel": "Warning"\r?\n}' + } + + It 'Should set "OTEL_DIAGNOSTICS.json" options' { + $config = Enable-OtelDiagnosticLog -LogDirectory "./logs" -FileSize 2048 -LogLevel Verbose + $config.FullName | Should -Exist + $config.FullName | Should -FileContentMatchMultiline '{\r?\n\s+"LogDirectory": "\.\/logs",\r?\n\s+"FileSize": 2048,\r?\n\s+"LogLevel": "Verbose"\r?\n}' + } + + } +} + +Describe 'Disabled-OtelDiagnosticLog' { + Context 'Remove existing file' { + BeforeEach { + Push-Location TestDrive:/ + $cwd = Get-PSDrive -Name TestDrive | Select-Object -ExpandProperty Root + [System.IO.Directory]::SetCurrentDirectory($cwd) + @" +{ + "LogDirectory": ".", + "FileSize": 32768, + "LogLevel": "Warning" +} +"@ | Set-Content TestDrive:/OTEL_DIAGNOSTICS.json + } + + AfterAll { + Pop-Location + [System.IO.Directory]::SetCurrentDirectory($PWD.Path) + } + + It 'Should remove "OTEL_DIAGNOSTICS.json"' { + Disable-OtelDiagnosticLog + + "TestDrive:/OTEL_DIAGNOSTICS.json" | Should -Not -Exist + } + + } +} + AfterAll { Remove-Module potel } \ No newline at end of file diff --git a/version.json b/version.json index 50ea6af..b6d60d5 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", - "version": "0.1", + "version": "0.2", "cloudBuild": { "buildNumber": { "enabled": true