Skip to content

Commit 823e6a9

Browse files
authored
Merge branch 'main' into rlamb/asp-net-classic
2 parents 4751a9a + 0c53ec2 commit 823e6a9

File tree

18 files changed

+351
-31
lines changed

18 files changed

+351
-31
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
name: Publish .NET SDK
2+
3+
inputs:
4+
aws-role-arn:
5+
description: 'The AWS role ARN to assume.'
6+
type: string
7+
required: true
8+
dry-run:
9+
description: 'Is this a dry run. If so no package will be published.'
10+
type: boolean
11+
required: true
12+
13+
outputs:
14+
package-hashes:
15+
description: 'Base64 encoded SHA256 hashes of published packages'
16+
value: ${{ steps.package-hashes.outputs.package-hashes }}
17+
18+
runs:
19+
using: composite
20+
steps:
21+
- uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.2.0
22+
name: Get secrets
23+
with:
24+
aws_assume_role: ${{ inputs.aws-role-arn }}
25+
ssm_parameter_pairs:
26+
'/production/common/releasing/digicert/host = DIGICERT_HOST,
27+
/production/common/releasing/digicert/api_key = DIGICERT_API_KEY,
28+
/production/common/releasing/digicert/client_cert_file_b64 = DIGICERT_CLIENT_CERT_FILE_B64,
29+
/production/common/releasing/digicert/client_cert_password = DIGICERT_CLIENT_CERT_PASSWORD,
30+
/production/common/releasing/digicert/code_signing_cert_sha1_hash = DIGICERT_CODE_SIGNING_CERT_SHA1_HASH,
31+
/production/common/releasing/nuget/api_key = NUGET_API_KEY'
32+
s3_path_pairs: 'launchdarkly-releaser/dotnet/LaunchDarkly.snk = LaunchDarkly.snk'
33+
34+
- name: Restore
35+
shell: bash
36+
working-directory: sdk/@launchdarkly/observability-dotnet
37+
run: dotnet restore
38+
39+
- name: Build
40+
shell: bash
41+
working-directory: ./sdk/@launchdarkly/observability-dotnet
42+
run: dotnet build ./src/LaunchDarkly.Observability/LaunchDarkly.Observability.csproj --no-restore -p:Configuration=Release
43+
44+
- name: Package
45+
shell: bash
46+
working-directory: ./sdk/@launchdarkly/observability-dotnet
47+
run: dotnet pack ./src/LaunchDarkly.Observability/LaunchDarkly.Observability.csproj --no-build --output nupkgs --configuration Release
48+
49+
- name: Publish Package
50+
if: ${{ inputs.dry-run == 'false' }}
51+
shell: bash
52+
working-directory: ./sdk/@launchdarkly/observability-dotnet
53+
run: |
54+
for pkg in $(find ./nupkgs -name '*.nupkg' -o -name '*.snupkg'); do
55+
echo "publishing ${pkg}"
56+
dotnet nuget push "${pkg}" --api-key ${{ env.NUGET_API_KEY }} --source https://www.nuget.org
57+
echo "published ${pkg}"
58+
done
59+
60+
- name: Hash nuget packages
61+
id: package-hashes
62+
shell: bash
63+
working-directory: ./sdk/@launchdarkly/observability-dotnet
64+
run: |
65+
echo "package-hashes=$(sha256sum ./nupkgs/*.nupkg ./nupkgs/*.snupkg | base64 -w0)" >> "$GITHUB_OUTPUT"

.github/workflows/dotnet-plugin.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,7 @@ jobs:
2929

3030
- run: dotnet test --no-restore
3131
working-directory: sdk/@launchdarkly/observability-dotnet
32+
33+
- name: Lint
34+
run: dotnet format --verify-no-changes
35+
working-directory: sdk/@launchdarkly/observability-dotnet

.github/workflows/manual-publish-docs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ on:
1111
- 'sdk/@launchdarkly/observability-node'
1212
- 'sdk/@launchdarkly/observability-python'
1313
- 'sdk/@launchdarkly/observability-react-native'
14+
- 'sdk/@launchdarkly/observability-dotnet'
1415
workflow_call:
1516
inputs:
1617
workspace_path:

.github/workflows/manual-publish.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ on:
3030
description: 'The tag name for the python package. Should be set when publishing a python package.'
3131
type: string
3232
required: false
33+
release_launchdarkly_dotnet:
34+
description: 'Should release @launchdarkly/observability-dotnet package.'
35+
type: boolean
36+
required: true
37+
dotnet_tag_name:
38+
description: 'The tag name for the dotnet package. Should be set when publishing a dotnet package.'
39+
type: string
40+
required: false
3341

3442
permissions:
3543
id-token: write
@@ -146,3 +154,34 @@ jobs:
146154
aws-role-arn: ${{ vars.AWS_ROLE_ARN }}
147155
dry-run: ${{ inputs.dry-run }}
148156
prerelease: ${{ inputs.prerelease }}
157+
158+
publish-dotnet-sdk:
159+
runs-on: ubuntu-latest
160+
if: ${{ inputs.release_launchdarkly_dotnet == true }}
161+
permissions:
162+
id-token: write
163+
outputs:
164+
package-hashes: ${{ steps.publish.outputs.package-hashes }}
165+
steps:
166+
- name: Checkout
167+
uses: actions/checkout@v4
168+
169+
- name: Publish .NET SDK
170+
id: publish
171+
uses: ./.github/actions/publish-dotnet-sdk
172+
with:
173+
aws-role-arn: ${{ vars.AWS_ROLE_ARN }}
174+
dry-run: ${{ inputs.dry-run }}
175+
176+
publish-dotnet-sdk-provenance:
177+
needs: ['publish-dotnet-sdk']
178+
if: ${{ inputs.release_launchdarkly_dotnet == true && inputs.dry-run == false }}
179+
permissions:
180+
actions: read
181+
id-token: write
182+
contents: write
183+
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
184+
with:
185+
base64-subjects: '${{ needs.publish-dotnet-sdk.outputs.package-hashes }}'
186+
upload-assets: true
187+
upload-tag-name: ${{ inputs.dotnet_tag_name }}

.github/workflows/release-please.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ jobs:
1616
python-plugin-tag-name: ${{ steps.release.outputs['sdk/@launchdarkly/observability-python--tag_name'] }}
1717
android-plugin-released: ${{ steps.release.outputs['sdk/@launchdarkly/observability-android--release_created'] }}
1818
android-plugin-tag-name: ${{ steps.release.outputs['sdk/@launchdarkly/observability-android--tag_name'] }}
19+
dotnet-plugin-released: ${{ steps.release.outputs['sdk/@launchdarkly/observability-dotnet--release_created'] }}
20+
dotnet-plugin-tag-name: ${{ steps.release.outputs['sdk/@launchdarkly/observability-dotnet--tag_name'] }}
1921
steps:
2022
- uses: googleapis/release-please-action@a02a34c4d625f9be7cb89156071d8567266a2445
2123
id: release
@@ -85,3 +87,47 @@ jobs:
8587
with:
8688
workspace-path: sdk/@launchdarkly/observability-android
8789
aws-role-arn: ${{ vars.AWS_ROLE_ARN }}
90+
91+
release-dotnet-plugin:
92+
runs-on: ubuntu-latest
93+
permissions:
94+
id-token: write # Used for publishing secrets.
95+
needs: ['release-package']
96+
outputs:
97+
package-hashes: ${{ steps.publish.outputs.package-hashes }}
98+
if: ${{ needs.release-package.outputs.dotnet-plugin-released == 'true' }}
99+
steps:
100+
- name: Checkout
101+
uses: actions/checkout@v4
102+
103+
- name: Publish .NET SDK
104+
id: publish
105+
uses: ./.github/actions/publish-dotnet-sdk
106+
with:
107+
aws-role-arn: ${{ vars.AWS_ROLE_ARN }}
108+
dry-run: false
109+
110+
release-dotnet-plugin-docs:
111+
runs-on: ubuntu-latest
112+
permissions:
113+
contents: write
114+
needs: ['release-package', 'release-dotnet-plugin']
115+
if: ${{ needs.release-package.outputs.dotnet-plugin-released == 'true' }}
116+
steps:
117+
- name: Build and Publish Docs
118+
uses: ./.github/workflows/manual-publish-docs.yml
119+
with:
120+
workspace_path: sdk/@launchdarkly/observability-dotnet
121+
122+
release-dotnet-sdk-provenance:
123+
needs: ['release-package', 'release-dotnet-plugin']
124+
if: ${{ needs.release-package.outputs.dotnet-plugin-released == 'true' }}
125+
permissions:
126+
actions: read
127+
id-token: write
128+
contents: write
129+
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
130+
with:
131+
base64-subjects: '${{ needs.release-dotnet-plugin.outputs.package-hashes }}'
132+
upload-assets: true
133+
upload-tag-name: ${{ needs.release-package.outputs.dotnet-plugin-tag-name }}

.release-please-manifest.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"sdk/@launchdarkly/observability-python": "0.1.0",
33
"go": "0.2.1",
4-
"sdk/@launchdarkly/observability-android": "0.4.0"
4+
"sdk/@launchdarkly/observability-android": "0.4.0",
5+
"sdk/@launchdarkly/observability-dotnet": "0.0.0"
56
}

e2e/android/app/build.gradle.kts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ plugins {
22
alias(libs.plugins.android.application)
33
alias(libs.plugins.kotlin.android)
44
alias(libs.plugins.kotlin.compose)
5+
id("net.bytebuddy.byte-buddy-gradle-plugin") version "1.17.6"
56
}
67

78
android {
@@ -52,6 +53,15 @@ dependencies {
5253
implementation("io.opentelemetry:opentelemetry-exporter-otlp:1.51.0")
5354
implementation("io.opentelemetry:opentelemetry-sdk-metrics:1.51.0")
5455

56+
// Android HTTP Url instrumentation
57+
implementation("io.opentelemetry.android.instrumentation:httpurlconnection-library:0.11.0-alpha")
58+
byteBuddy("io.opentelemetry.android.instrumentation:httpurlconnection-agent:0.11.0-alpha")
59+
60+
// OkHTTP instrumentation
61+
implementation("io.opentelemetry.android.instrumentation:okhttp3-library:0.11.0-alpha")
62+
byteBuddy("io.opentelemetry.android.instrumentation:okhttp3-agent:0.11.0-alpha")
63+
implementation("com.squareup.okhttp3:okhttp:4.12.0")
64+
5565
implementation("com.google.android.material:material:1.12.0")
5666
implementation(libs.androidx.core.ktx)
5767
implementation(libs.androidx.lifecycle.runtime.ktx)

e2e/android/app/src/main/java/com/example/androidobservability/MainActivity.kt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ class MainActivity : ComponentActivity() {
3737
) {
3838
Text("Go to Secondary Activity")
3939
}
40+
Button(
41+
onClick = {
42+
viewModel.triggerHttpRequests()
43+
}
44+
) {
45+
Text("Trigger HTTP Request")
46+
}
4047
Button(
4148
onClick = {
4249
viewModel.triggerMetric()
@@ -60,17 +67,10 @@ class MainActivity : ComponentActivity() {
6067
}
6168
Button(
6269
onClick = {
63-
viewModel.triggerStartSpan()
64-
}
65-
) {
66-
Text("Trigger Start Span")
67-
}
68-
Button(
69-
onClick = {
70-
viewModel.triggerStopSpan()
70+
viewModel.triggerNestedSpans()
7171
}
7272
) {
73-
Text("Trigger Stop Span")
73+
Text("Trigger Nested Spans")
7474
}
7575
Button(
7676
onClick = {
Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
package com.example.androidobservability
22

33
import androidx.lifecycle.ViewModel
4+
import androidx.lifecycle.viewModelScope
45
import com.launchdarkly.observability.interfaces.Metric
56
import com.launchdarkly.observability.sdk.LDObserve
6-
import com.launchdarkly.sdk.android.LDClient
77
import io.opentelemetry.api.common.AttributeKey
88
import io.opentelemetry.api.common.Attributes
99
import io.opentelemetry.api.logs.Severity
10-
import io.opentelemetry.api.trace.Span
11-
import java.net.SocketTimeoutException
10+
import kotlinx.coroutines.Dispatchers
11+
import kotlinx.coroutines.launch
12+
import okhttp3.OkHttpClient
13+
import okhttp3.Request
14+
import java.io.BufferedInputStream
15+
import java.net.HttpURLConnection
16+
import java.net.URL
1217

1318
class ViewModel : ViewModel() {
1419

15-
private var lastSpan: Span? = null
16-
1720
fun triggerMetric() {
1821
LDObserve.recordMetric(Metric("test", 50.0))
1922
}
@@ -33,20 +36,59 @@ class ViewModel : ViewModel() {
3336
)
3437
}
3538

36-
fun triggerStartSpan() {
37-
val newSpan = LDObserve.startSpan("FakeSpan", Attributes.empty())
38-
newSpan.makeCurrent()
39-
lastSpan = newSpan
40-
LDClient.get().boolVariation("my-boolean-flag", false)
41-
}
42-
43-
fun triggerStopSpan() {
44-
// TODO O11Y-397: for some reason stopped spans are stacking, the current span might be the problem
45-
lastSpan?.end()
46-
lastSpan = null
39+
fun triggerNestedSpans() {
40+
viewModelScope.launch(Dispatchers.IO) {
41+
val newSpan0 = LDObserve.startSpan("FakeSpan", Attributes.empty())
42+
newSpan0.makeCurrent().use {
43+
val newSpan1 = LDObserve.startSpan("FakeSpan1", Attributes.empty())
44+
newSpan1.makeCurrent().use {
45+
val newSpan2 = LDObserve.startSpan("FakeSpan2", Attributes.empty())
46+
newSpan2.makeCurrent().use {
47+
sendOkHttpRequest()
48+
sendURLRequest()
49+
newSpan2.end()
50+
}
51+
newSpan1.end()
52+
}
53+
newSpan0.end()
54+
}
55+
}
4756
}
4857

4958
fun triggerCrash() {
5059
throw RuntimeException("Failed to connect to bogus server.")
5160
}
61+
62+
fun triggerHttpRequests() {
63+
viewModelScope.launch(Dispatchers.IO) {
64+
sendOkHttpRequest()
65+
sendURLRequest()
66+
}
67+
}
68+
69+
private fun sendOkHttpRequest() {
70+
// Create HTTP client
71+
val client = OkHttpClient()
72+
73+
// Build request
74+
val request: Request = Request.Builder()
75+
.url("https://www.google.com")
76+
.build()
77+
78+
client.newCall(request).execute().use { response ->
79+
println("Response code: " + response.code)
80+
println("Response body: " + response.body?.string())
81+
}
82+
}
83+
84+
private fun sendURLRequest() {
85+
val url = URL("https://www.android.com/")
86+
val urlConnection = url.openConnection() as HttpURLConnection
87+
try {
88+
val output = BufferedInputStream(urlConnection.inputStream).bufferedReader().use { it.readText() }
89+
println("URLRequest output: $output")
90+
} finally {
91+
urlConnection.disconnect()
92+
}
93+
}
5294
}

release-please-config.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@
2525
"include-v-in-tag": true,
2626
"include-component-in-tag": true,
2727
"extra-files": ["version.go"]
28+
},
29+
"sdk/@launchdarkly/observability-dotnet": {
30+
"release-as": "0.1.0",
31+
"bump-minor-pre-major": true,
32+
"package-name": "launchdarkly-observability-dotnet",
33+
"release-type": "simple",
34+
"include-v-in-tag": false,
35+
"include-component-in-tag": true,
36+
"extra-files": [
37+
"src/LaunchDarkly.Observability/LaunchDarkly.Observability.csproj"
38+
]
2839
}
2940
}
3041
}

0 commit comments

Comments
 (0)