Skip to content

System.Diagnostics.ActivitySource support for observability #83

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,22 @@
"version": "9.0.2",
"commands": [
"paket"
]
],
"rollForward": false
},
"fantomas": {
"version": "6.2.3",
"commands": [
"fantomas"
]
],
"rollForward": false
},
"sleet": {
"version": "6.4.0",
"commands": [
"sleet"
],
"rollForward": false
}
}
}
4 changes: 4 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
### 0.12.4-beta
* Added OpenTelemetry instrumentation

### 0.12.3-beta
* Removed erroneous `Dotnet.Reproduciblebuilds` dependency [#75](https://github.com/fsprojects/FSharp.AWS.DynamoDB/pull/75)

### 0.12.2-beta
* (breaking) Revised multi-table transaction API (thanks @bartelink)

Expand Down
10 changes: 10 additions & 0 deletions build.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ let summary = "An F# wrapper over the standard Amazon.DynamoDB library"
let gitOwner = "fsprojects"
let gitName = "FSharp.AWS.DynamoDB"
let gitHome = "https://github.com/" + gitOwner
let sleetSource = "codesplice"

// --------------------------------------------------------------------------------------
// Build variables
Expand Down Expand Up @@ -196,16 +197,25 @@ Target.create "Push" (fun _ ->
Source = Some "https://api.nuget.org/v3/index.json" }
DotNet.nugetPush (fun o -> o.WithPushParams pushParams) (sprintf "%s**.*.nupkg" nugetDir))

Target.create "PushInternal" (fun _ ->
CreateProcess.fromRawCommand "dotnet" [ "sleet"; "push"; nugetDir; "--source"; sleetSource; "--force" ]
|> CreateProcess.ensureExitCodeWithMessage "Error while running 'sleet push'"
|> Proc.run
|> ignore)

// --------------------------------------------------------------------------------------
// Build order
// --------------------------------------------------------------------------------------
Target.create "Default" DoNothing
Target.create "ReleaseInternal" DoNothing
Target.create "Release" DoNothing

"Clean" ==> "AssemblyInfo" ==> "Restore" ==> "Build" ==> "Test" ==> "Default"

"Clean" ==> "AssemblyInfo" ==> "Restore" ==> "BuildRelease" ==> "Docs"

"Default" ==> "Pack" ==> "PushInternal" ==> "ReleaseInternal"

"Default" ==> "Pack" ==> "ReleaseGitHub" ==> "Push" ==> "Release"

Target.runOrDefaultWithArguments "Default"
8 changes: 4 additions & 4 deletions paket.dependencies
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
source https://api.nuget.org/v3/index.json

storage: none
framework: net80, netstandard20, netstandard21
framework: net90, netstandard20, netstandard21

# copy_local: true because this is a build-time dependency only
nuget Dotnet.ReproducibleBuilds copy_local: true
Expand All @@ -15,14 +15,14 @@ nuget Unquote ~> 6.1.0
nuget FSharp.Core >= 4.7.2 content: false, lowest_matching: true

nuget AWSSDK.DynamoDBv2 ~> 3.7.5

nuget System.Diagnostics.DiagnosticSource >= 6.0.0
github eiriktsarpalis/TypeShape:10.0.0 src/TypeShape/TypeShape.fs

group Test
source https://api.nuget.org/v3/index.json
framework: net80
framework: net90

nuget FsCheck
nuget FsCheck ~> 2.16.6
nuget Microsoft.NET.Test.Sdk
nuget xunit
nuget xunit.runner.visualstudio
104 changes: 43 additions & 61 deletions paket.lock
Original file line number Diff line number Diff line change
@@ -1,80 +1,62 @@
STORAGE: NONE
RESTRICTION: || (== net8.0) (== netstandard2.0) (== netstandard2.1)
RESTRICTION: || (== net9.0) (== netstandard2.0) (== netstandard2.1)
NUGET
remote: https://api.nuget.org/v3/index.json
AWSSDK.Core (3.7.300.11)
Microsoft.Bcl.AsyncInterfaces (>= 1.1) - restriction: || (&& (== net8.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1)
AWSSDK.DynamoDBv2 (3.7.300.11)
AWSSDK.Core (>= 3.7.300.11 < 4.0)
DotNet.ReproducibleBuilds (1.1.1) - copy_local: true
Microsoft.SourceLink.AzureRepos.Git (>= 1.1.1)
Microsoft.SourceLink.Bitbucket.Git (>= 1.1.1)
Microsoft.SourceLink.GitHub (>= 1.1.1)
Microsoft.SourceLink.GitLab (>= 1.1.1)
AWSSDK.Core (3.7.402.43)
Microsoft.Bcl.AsyncInterfaces (>= 1.1) - restriction: || (&& (== net9.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1)
AWSSDK.DynamoDBv2 (3.7.406.25)
AWSSDK.Core (>= 3.7.402.43 < 4.0)
DotNet.ReproducibleBuilds (1.2.25) - copy_local: true
FSharp.Core (4.7.2)
Microsoft.Bcl.AsyncInterfaces (8.0) - restriction: || (&& (== net8.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1)
System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net8.0) (>= net462)) (&& (== net8.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net462))
Microsoft.Build.Tasks.Git (8.0) - copy_local: true
Microsoft.SourceLink.AzureRepos.Git (8.0) - copy_local: true
Microsoft.Build.Tasks.Git (>= 8.0)
Microsoft.SourceLink.Common (>= 8.0)
Microsoft.SourceLink.Bitbucket.Git (8.0) - copy_local: true
Microsoft.Build.Tasks.Git (>= 8.0)
Microsoft.SourceLink.Common (>= 8.0)
Microsoft.SourceLink.Common (8.0) - copy_local: true
Microsoft.SourceLink.GitHub (8.0) - copy_local: true
Microsoft.Build.Tasks.Git (>= 8.0)
Microsoft.SourceLink.Common (>= 8.0)
Microsoft.SourceLink.GitLab (8.0) - copy_local: true
Microsoft.Build.Tasks.Git (>= 8.0)
Microsoft.SourceLink.Common (>= 8.0)
System.Runtime.CompilerServices.Unsafe (6.0) - restriction: || (&& (== net8.0) (>= net461)) (&& (== net8.0) (>= net462)) (&& (== net8.0) (< netcoreapp2.1) (< netstandard2.1)) (&& (== net8.0) (< netstandard1.0)) (&& (== net8.0) (< netstandard2.0)) (&& (== net8.0) (>= wp8)) (== netstandard2.0) (&& (== netstandard2.1) (>= net462))
System.Threading.Tasks.Extensions (4.5.4) - restriction: || (&& (== net8.0) (>= net462)) (&& (== net8.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net462))
System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (== net8.0) (>= net461)) (&& (== net8.0) (< netcoreapp2.1)) (&& (== net8.0) (< netstandard1.0)) (&& (== net8.0) (< netstandard2.0)) (&& (== net8.0) (>= wp8)) (== netstandard2.0) (== netstandard2.1)
Microsoft.Bcl.AsyncInterfaces (9.0.4) - restriction: || (&& (== net9.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1)
System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net9.0) (>= net462)) (&& (== net9.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net462))
System.Buffers (4.6.1) - restriction: || (&& (== net9.0) (>= net462)) (&& (== net9.0) (< netcoreapp2.1) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net462))
System.Diagnostics.DiagnosticSource (9.0.4)
System.Memory (>= 4.5.5) - restriction: || (&& (== net9.0) (>= net462)) (&& (== net9.0) (< net8.0)) (== netstandard2.0) (== netstandard2.1)
System.Runtime.CompilerServices.Unsafe (>= 6.0) - restriction: || (&& (== net9.0) (>= net462)) (&& (== net9.0) (< net8.0)) (== netstandard2.0) (== netstandard2.1)
System.Memory (4.6.3) - restriction: || (&& (== net9.0) (>= net462)) (&& (== net9.0) (< net8.0)) (== netstandard2.0) (== netstandard2.1)
System.Buffers (>= 4.6.1) - restriction: || (&& (== net9.0) (>= net462)) (&& (== net9.0) (< netcoreapp2.1) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net462))
System.Numerics.Vectors (>= 4.6.1) - restriction: || (&& (== net9.0) (>= net462)) (&& (== net9.0) (< netcoreapp2.1) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net462))
System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (&& (== net9.0) (>= net462)) (&& (== net9.0) (< netcoreapp2.1) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net462))
System.Numerics.Vectors (4.6.1) - restriction: || (&& (== net9.0) (>= net462)) (&& (== net9.0) (< netcoreapp2.1) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net462))
System.Runtime.CompilerServices.Unsafe (6.1.2) - restriction: || (&& (== net9.0) (>= net462)) (&& (== net9.0) (< net8.0)) (&& (== net9.0) (< netcoreapp2.1) (< netstandard2.1)) (== netstandard2.0) (== netstandard2.1)
System.Threading.Tasks.Extensions (4.6.3) - restriction: || (&& (== net9.0) (>= net462)) (&& (== net9.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net462))
System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (&& (== net9.0) (>= net462)) (&& (== net9.0) (< netcoreapp2.1) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net462))
Unquote (6.1)
FSharp.Core (>= 4.7.2)
GITHUB
remote: eiriktsarpalis/TypeShape
src/TypeShape/TypeShape.fs (6e7fe07c799de723de7e4b32d64a4fd6c1697c7f)
GROUP Test
RESTRICTION: == net8.0
RESTRICTION: == net9.0
NUGET
remote: https://api.nuget.org/v3/index.json
FsCheck (2.16.6)
FSharp.Core (>= 4.2.3)
FSharp.Core (8.0.100)
Microsoft.CodeCoverage (17.8)
Microsoft.NET.Test.Sdk (17.8)
Microsoft.CodeCoverage (>= 17.8)
Microsoft.TestPlatform.TestHost (>= 17.8)
Microsoft.NETCore.Platforms (7.0.4)
Microsoft.TestPlatform.ObjectModel (17.8)
NuGet.Frameworks (>= 6.5)
FSharp.Core (9.0.202)
Microsoft.CodeCoverage (17.13)
Microsoft.NET.Test.Sdk (17.13)
Microsoft.CodeCoverage (>= 17.13)
Microsoft.TestPlatform.TestHost (>= 17.13)
Microsoft.TestPlatform.ObjectModel (17.13)
System.Reflection.Metadata (>= 1.6)
Microsoft.TestPlatform.TestHost (17.8)
Microsoft.TestPlatform.ObjectModel (>= 17.8)
Microsoft.TestPlatform.TestHost (17.13)
Microsoft.TestPlatform.ObjectModel (>= 17.13)
Newtonsoft.Json (>= 13.0.1)
NETStandard.Library (2.0.3)
Microsoft.NETCore.Platforms (>= 1.1)
Newtonsoft.Json (13.0.3)
NuGet.Frameworks (6.8)
System.Collections.Immutable (8.0)
System.Reflection.Metadata (8.0)
System.Collections.Immutable (>= 8.0)
xunit (2.6.2)
xunit.analyzers (>= 1.6)
xunit.assert (>= 2.6.2)
xunit.core (2.6.2)
System.Reflection.Metadata (9.0.4)
xunit (2.9.3)
xunit.analyzers (>= 1.18)
xunit.assert (>= 2.9.3)
xunit.core (2.9.3)
xunit.abstractions (2.0.3)
xunit.analyzers (1.6)
xunit.assert (2.6.2)
xunit.core (2.6.2)
xunit.extensibility.core (2.6.2)
xunit.extensibility.execution (2.6.2)
xunit.extensibility.core (2.6.2)
NETStandard.Library (>= 1.6.1)
xunit.analyzers (1.21)
xunit.assert (2.9.3)
xunit.core (2.9.3)
xunit.extensibility.core (2.9.3)
xunit.extensibility.execution (2.9.3)
xunit.extensibility.core (2.9.3)
xunit.abstractions (>= 2.0.3)
xunit.extensibility.execution (2.6.2)
NETStandard.Library (>= 1.6.1)
xunit.extensibility.core (2.6.2)
xunit.runner.visualstudio (2.5.4)
xunit.extensibility.execution (2.9.3)
xunit.extensibility.core (2.9.3)
xunit.runner.visualstudio (3.0.2)
132 changes: 132 additions & 0 deletions src/FSharp.AWS.DynamoDB/Diagnostics.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
namespace FSharp.AWS.DynamoDB

module internal Activity =
open System.Diagnostics

let private activitySource = new ActivitySource "FSharp.AWS.DynamoDB"

let hasListeners () : bool = activitySource.HasListeners()

let private addTag (tag: string) (value: obj) (activity: Activity) =
if activity <> null then
activity.AddTag(tag, value)
else
activity

/// Adds the hard-coded `db.system`, `rpc.system`, and `rpc.service` tags to the `Activity`.
let addStandardTags (activity: Activity) =
activity
|> addTag "db.system" "dynamodb"
|> addTag "rpc.system" "aws-api"
|> addTag "rpc.service" "DynamoDB"

let addTableName (tableName: string) = addTag "aws.dynamodb.table_names" [| tableName |]

let addTableNames (tableNames: string seq) = addTag "aws.dynamodb.table_names" (Array.ofSeq tableNames)

let addOperation (operation: string) = addTag "rpc.method" operation

let addConsistentRead (consistentRead: bool) = addTag "aws.dynamodb.consistent_read" consistentRead

let addScanIndexForward (scanIndexForward: bool) = addTag "aws.dynamodb.scan_forward" scanIndexForward

let addLimit (limit: int option) (activity: Activity) =
match limit with
| Some l -> addTag "aws.dynamodb.limit" l activity
| None -> activity

let addIndexName (indexName: string option) (activity: Activity) =
match indexName with
| Some i -> addTag "aws.dynamodb.index_name" i activity
| None -> activity

let addProjection (projection: string) = addTag "aws.dynamodb.projection" projection

let addCount (count: int) = addTag "aws.dynamodb.count" count

let addScannedCount (scannedCount: int) = addTag "aws.dynamodb.scanned_count" scannedCount

/// Starts a new activity for a DynamoDB operation named "{operation} {tableName}" (eg "GetItem MyTable").
/// Sets the standard tags for all table operations and returns the `Activity` for further customization.
let startTableActivity (tableName: string) (operation: string) : Activity =
activitySource.StartActivity(sprintf "%s %s" operation tableName, ActivityKind.Client)
|> addStandardTags
|> addTableName tableName
|> addOperation operation

/// Starts a new activity for a multi-table DynamoDB operation (eg "BatchGetItem").
/// Sets the standard tags for all table operations and returns the `Activity` for further customization.
let startMultipleTableActivity (tableNames: string seq) (operation: string) : Activity =
activitySource.StartActivity(operation, ActivityKind.Client)
|> addStandardTags
|> addTableNames tableNames
|> addOperation operation

let addException (ex: exn) (activity: Activity) =
if activity <> null then
activity.AddException ex
else
activity

let stop (activity: Activity) =
if activity <> null then
activity.Stop()

module internal Meter =
open System.Diagnostics.Metrics
open System.Collections.Generic

let private meter = new Meter "FSharp.AWS.DynamoDB"

let private consumedReadCapacity =
meter.CreateHistogram<float>(
"db.client.operation.consumed_read_capacity",
unit = "RCU",
description = "Consumed read capacity units (RCU) for the DynamoDB operation",
tags = [ KeyValuePair("db.system.name", "aws.dynamodb" :> obj) ]
)

let private consumedWriteCapacity =
meter.CreateHistogram<float>(
"db.client.operation.consumed_write_capacity",
unit = "WCU",
description = "Consumed write capacity units (WCU) for the DynamoDB operation",
tags = [ KeyValuePair("db.system.name", "aws.dynamodb" :> obj) ]
)

let recordConsumedReadCapacity (tableName: string) (operation: string) (rcu: float) =
if rcu > 0.0 then
consumedReadCapacity.Record(
rcu,
KeyValuePair("db.collection.name", tableName :> obj),
KeyValuePair("db.operation.name", operation :> obj)
)

let recordConsumedWriteCapacity (tableName: string) (operation: string) (wcu: float) =
if wcu > 0.0 then
consumedWriteCapacity.Record(
wcu,
KeyValuePair("db.collection.name", tableName :> obj),
KeyValuePair("db.operation.name", operation :> obj)
)

let recordConsumedCapacity (tableName: string) (operation: string) (capacity : Amazon.DynamoDBv2.Model.ConsumedCapacity) =
if capacity <> null then
recordConsumedReadCapacity tableName operation capacity.ReadCapacityUnits
recordConsumedWriteCapacity tableName operation capacity.WriteCapacityUnits

module internal Task =
open System.Threading.Tasks
open System.Diagnostics

/// Adds an exception to the activity if the task is faulted
/// Handles unwrapping the inner exception if present
let addActivityException (activity: Activity) (task: Task<'a>) =
if task.IsFaulted then
let exn =
if task.Exception.InnerExceptions.Count = 1 then
task.Exception.InnerExceptions[0]
else
task.Exception
Activity.addException exn activity |> ignore
task
4 changes: 2 additions & 2 deletions src/FSharp.AWS.DynamoDB/FSharp.AWS.DynamoDB.fsproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
Expand Down Expand Up @@ -35,10 +34,11 @@
<Compile Include="Expression\UpdateExpr.fs" />
<Compile Include="Expression\ProjectionExpr.fs" />
<Compile Include="Expression\ExpressionContainers.fs" />
<Compile Include="Diagnostics.fs" />
<Compile Include="RecordTemplate.fs" />
<Compile Include="TableContext.fs" />
<Compile Include="Extensions.fs" />
<None Include="Script.fsx" />
</ItemGroup>
<Import Project="..\..\.paket\Paket.Restore.targets" />
</Project>
</Project>
2 changes: 1 addition & 1 deletion src/FSharp.AWS.DynamoDB/Script.fsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#if USE_PUBLISHED_NUGET // If you don't want to do a local build first
#r "nuget: FSharp.AWS.DynamoDB, *-*" // *-* to white-list the fact that all releases to date have been `-beta` sufficed
#else
#I "../../tests/FSharp.AWS.DynamoDB.Tests/bin/Debug/net8.0/"
#I "../../tests/FSharp.AWS.DynamoDB.Tests/bin/Debug/net9.0/"
#r "AWSSDK.Core.dll"
#r "AWSSDK.DynamoDBv2.dll"
#r "FSharp.AWS.DynamoDB.dll"
Expand Down
Loading