diff --git a/.github/workflows/check-deployed-package.yml b/.github/workflows/check-deployed-package.yml
index e086219..80813b2 100644
--- a/.github/workflows/check-deployed-package.yml
+++ b/.github/workflows/check-deployed-package.yml
@@ -1,41 +1,35 @@
name: Check deployed package
+# CI calls it after each release; run it by hand to check any version from any branch.
on:
+ workflow_call:
+ inputs:
+ version:
+ type: string
+ required: true
+ secrets: # run.sh fails with a clear message when one is missing
+ LOGDASH_API_KEY:
+ required: false
+ LOGDASH_PERSONAL_API_KEY:
+ required: false
workflow_dispatch:
- workflow_run:
- workflows: ['CI/CD Pipeline']
- types:
- - completed
+ inputs:
+ version:
+ description: Version to check; empty checks the latest release
+ type: string
+
+permissions:
+ contents: read
jobs:
check-deployed-package:
name: Check deployed package
runs-on: ubuntu-latest
- if: >
- github.event.workflow_run.conclusion == 'success' &&
- github.event.workflow_run.event == 'push' &&
- startsWith(github.event.workflow_run.head_branch, 'v') &&
- github.event.workflow_run.head_branch != github.event.workflow_run.repository.default_branch
- permissions:
- contents: read
- packages: read
-
+ timeout-minutes: 75 # up to an hour waiting for Maven Central
steps:
- - name: Checkout repository
- uses: actions/checkout@v4
-
- - name: Make run script executable
- run: chmod +x check-deployed-package/run.sh
-
- - name: Verify environment variables
- run: |
- echo "GITHUB_ACTOR: ${{ github.actor }}"
- echo "Has GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN != '' }}"
- echo "Has LOGDASH_API_KEY: ${{ secrets.LOGDASH_API_KEY != '' }}"
-
- - name: Run LogDash demo
+ - uses: actions/checkout@v7
+ - run: ./check-deployed-package/run.sh
env:
+ LOGDASH_VERSION: ${{ inputs.version }}
LOGDASH_API_KEY: ${{ secrets.LOGDASH_API_KEY }}
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- GITHUB_ACTOR: ${{ github.actor }}
- run: ./check-deployed-package/run.sh
\ No newline at end of file
+ LOGDASH_PERSONAL_API_KEY: ${{ secrets.LOGDASH_PERSONAL_API_KEY }}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 79f6326..f7add75 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,31 +2,29 @@ name: CI/CD Pipeline
on:
push:
- branches: [ main, dev ]
- tags: [ 'v*' ]
+ branches: [ main ]
pull_request:
- branches: [ main, dev ]
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ # A release in progress must finish; a newer merge waits and releases after it.
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
- contents: write
- actions: read
- checks: write
- security-events: write
- pull-requests: write
+ contents: read
+
+defaults:
+ run:
+ shell: bash # with pipefail, so a failing command in a pipe fails the step
env:
JAVA_VERSION: '17'
MAVEN_OPTS: >
- -Dmaven.repo.local=.m2/repository
- -Xmx2048m
- -XX:+UseG1GC
+ -Xmx2048m
+ -XX:+UseG1GC
-Daether.connector.http.connectionMaxTtl=25
-Dmaven.artifact.threads=8
-concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}
- cancel-in-progress: true
-
jobs:
validate:
name: Code Quality & Security
@@ -35,27 +33,29 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Setup JDK
- uses: actions/setup-java@v4
+ uses: actions/setup-java@v6
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: 'temurin'
+ cache: maven
- name: Validate Project
- uses: nick-fields/retry@v3
+ uses: nick-fields/retry@v4
with:
timeout_minutes: 10
max_attempts: 2
retry_wait_seconds: 30
command: mvn clean validate compile -B --no-transfer-progress -DskipTests
+ # The quality profile's execution, which fails on a warning; a bare dependency:analyze only warns.
- name: Verify Dependencies
run: |
- mvn dependency:analyze -B --no-transfer-progress -Pquality
+ mvn test-compile dependency:analyze-only@analyze-dependencies -B --no-transfer-progress -Pquality
mvn dependency:tree -B --no-transfer-progress | tee dependency-tree.txt
- name: Code Style Check (Spotless)
@@ -65,7 +65,7 @@ jobs:
run: mvn spotbugs:check -B --no-transfer-progress
- name: Upload Dependency Tree
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v7
with:
name: dependency-analysis
path: dependency-tree.txt
@@ -76,6 +76,10 @@ jobs:
runs-on: ubuntu-latest
needs: validate
timeout-minutes: 25
+ permissions:
+ contents: read
+ actions: read
+ checks: write # the test report
strategy:
fail-fast: false
matrix:
@@ -83,445 +87,175 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v7
- name: Setup JDK ${{ matrix.java }}
- uses: actions/setup-java@v4
+ uses: actions/setup-java@v6
with:
java-version: ${{ matrix.java }}
distribution: 'temurin'
+ cache: maven
- name: Run Tests & Coverage Check
- uses: nick-fields/retry@v3
+ uses: nick-fields/retry@v4
with:
timeout_minutes: 20
max_attempts: 3
retry_wait_seconds: 30
command: mvn clean verify -B --no-transfer-progress -Djava.version=${{ matrix.java }}
- - name: List test report files
- if: always() && matrix.java == 17
- run: |
- echo "Surefire reports:"
- ls -l target/surefire-reports || true
- echo "Failsafe reports:"
- ls -l target/failsafe-reports || true
- echo "JaCoCo reports:"
- ls -l target/site/jacoco* || true
-
- name: Upload coverage reports to Codecov
if: matrix.java == 17
- uses: codecov/codecov-action@v5
+ uses: codecov/codecov-action@v7
with:
files: target/site/jacoco-merged/jacoco.xml,target/site/jacoco/jacoco.xml
token: ${{ secrets.CODECOV_TOKEN }}
- fail_ci_if_error: false
+ fail_ci_if_error: true
- name: Upload Test Results
- uses: dorny/test-reporter@v1
- if: always() && matrix.java == 17
+ uses: dorny/test-reporter@v3
+ if: ${{ !cancelled() && matrix.java == 17 }}
with:
name: Test Results (Java ${{ matrix.java }})
path: target/surefire-reports/TEST-*.xml,target/failsafe-reports/TEST-*.xml
reporter: java-junit
- fail-on-error: false
+ fail-on-error: false # the test step has failed the job already
- build:
- name: Build & Package
+ test-scripts:
+ name: Test Suite (release scripts)
runs-on: ubuntu-latest
- needs: [ validate, test ]
- timeout-minutes: 15
- outputs:
- version: ${{ steps.version.outputs.version }}
- is-snapshot: ${{ steps.version.outputs.is-snapshot }}
+ timeout-minutes: 5
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v7
- - name: Setup JDK
- uses: actions/setup-java@v4
+ - name: Setup Node
+ uses: actions/setup-node@v7
with:
- java-version: ${{ env.JAVA_VERSION }}
- distribution: 'temurin'
+ node-version: 24
- - name: Extract Version
- id: version
- run: |
- VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
- echo "version=$VERSION" >> $GITHUB_OUTPUT
- echo "is-snapshot=$(echo $VERSION | grep -q SNAPSHOT && echo true || echo false)" >> $GITHUB_OUTPUT
-
- - name: Build Package
- uses: nick-fields/retry@v3
- with:
- timeout_minutes: 10
- max_attempts: 2
- retry_wait_seconds: 30
- command: mvn clean package -B --no-transfer-progress -DskipTests
-
- - name: Generate Documentation
- run: mvn javadoc:javadoc -B --no-transfer-progress
-
- - name: Verify JAR Structure
- run: |
- jar -tf target/logdash-*.jar | head -20
- echo "JAR size: $(du -h target/logdash-*.jar | cut -f1)"
-
- - name: Upload Build Artifacts
- uses: actions/upload-artifact@v4
- with:
- name: build-artifacts-${{ steps.version.outputs.version }}
- path: |
- target/*-${{ steps.version.outputs.version }}.jar
- !target/*-tests.jar
- !target/original-*.jar
- target/site/apidocs/**
- retention-days: ${{ steps.version.outputs.is-snapshot == 'true' && 7 || 90 }}
+ - name: Run Tests
+ run: node --test 'scripts/*.test.ts'
security-scan:
name: Security Scanning
runs-on: ubuntu-latest
needs: validate
timeout-minutes: 15
- if: >
- (github.event_name == 'push' && github.ref == 'refs/heads/main') ||
- (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'security-scan')) ||
- startsWith(github.ref, 'refs/tags/v')
+ if: github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'security-scan')
+ permissions:
+ contents: read
+ security-events: write # the SARIF upload
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v7
- name: Setup JDK
- uses: actions/setup-java@v4
+ uses: actions/setup-java@v6
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: 'temurin'
+ cache: maven
- - name: Build for Security Scan
- run: mvn clean compile -B --no-transfer-progress -DskipTests
+ # Online, Trivy fetches the dependencies' poms from Maven Central, which rate-limits it (429) and
+ # fails the scan. Maven puts them in ~/.m2 instead, where Trivy's offline scan finds them.
+ - name: Resolve Dependencies for Security Scan
+ run: for pom in pom.xml examples/*/pom.xml; do mvn dependency:tree -B --no-transfer-progress -q -f "$pom"; done
- name: Run Trivy Scan
- uses: aquasecurity/trivy-action@master
+ uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
+ env:
+ TRIVY_OFFLINE_SCAN: true
- name: Upload SARIF
- uses: github/codeql-action/upload-sarif@v3
- if: always()
+ if: hashFiles('trivy-results.sarif') != ''
+ uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: 'trivy-results.sarif'
- continue-on-error: true
- github-release:
- name: Release to GitHub Packages
+ # The version the merged commits call for; empty when none of them is a feat, fix, perf, or breaking change.
+ version:
+ if: github.event_name == 'push'
runs-on: ubuntu-latest
- needs: [ build, security-scan ]
- timeout-minutes: 15
- if: startsWith(github.ref, 'refs/tags/v')
-
- permissions:
- contents: write
- packages: write
-
+ outputs:
+ next: ${{ steps.next.outputs.version }}
steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Setup JDK
- uses: actions/setup-java@v4
+ - uses: actions/checkout@v7
with:
- java-version: ${{ env.JAVA_VERSION }}
- distribution: 'temurin'
-
- - name: Configure Maven Settings
- uses: whelk-io/maven-settings-xml-action@v22
+ fetch-depth: 0 # the tags and commits since the last release
+ - uses: actions/setup-node@v7
with:
- servers: |
- [
- {
- "id": "github",
- "username": "${env.GITHUB_ACTOR}",
- "password": "${env.GITHUB_TOKEN}"
- }
- ]
-
- - name: Extract Version Info
- id: version
- run: |
- VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
- echo "version=$VERSION" >> $GITHUB_OUTPUT
- echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
-
- # Validate version matches tag
- if [[ "v$VERSION" != "${GITHUB_REF#refs/tags/}" ]]; then
- echo "::error::Version mismatch: POM version ($VERSION) doesn't match tag (${GITHUB_REF#refs/tags/})"
- exit 1
- fi
-
- - name: Check if version exists in GitHub Packages
- run: |
- VERSION=${{ steps.version.outputs.version }}
- # Check if version already exists in GitHub Packages
- if gh api /orgs/logdash-io/packages/maven/io.logdash.logdash/versions --jq '.[] | .name' | grep -q "^$VERSION$"; then
- echo "::warning::Version $VERSION already exists in GitHub Packages"
- echo "Either delete the existing version or bump the version in pom.xml"
- else
- echo "✅ Version $VERSION is available for release"
- fi
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Build and Deploy to GitHub Packages
- run: |
- mvn clean deploy -B --no-transfer-progress \
- -Pgithub-release \
- -DperformRelease=true \
- -DskipTests=true
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Notify GitHub Release Success
+ node-version: 24
+ - id: next
run: |
- echo "✅ Successfully deployed logdash:${{ steps.version.outputs.version }} to GitHub Packages"
- echo "📦 Available at: https://github.com/logdash-io/java-sdk/packages"
+ next=$(node scripts/version.ts) # on its own line, so a crash fails the step instead of releasing nothing
+ echo "version=$next" >> "$GITHUB_OUTPUT"
- maven-central-release:
- name: Release to Maven Central
+ # Publishes the merge to Maven Central, then tags it with a GitHub release.
+ release:
+ needs: [ validate, test, test-scripts, security-scan, version ]
+ if: needs.version.outputs.next != ''
runs-on: ubuntu-latest
- needs: [ build, security-scan ]
- timeout-minutes: 30
- if: startsWith(github.ref, 'refs/tags/v')
-
+ timeout-minutes: 45
+ permissions:
+ contents: write # the release and its tag
+ env:
+ V: ${{ needs.version.outputs.next }}
steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Setup JDK
- uses: actions/setup-java@v4
+ - uses: actions/checkout@v7
+ with:
+ persist-credentials: false # keeps the token off disk while Maven plugins run
+ # A rerun after a deploy that succeeded skips to the tag, since Central rejects a version twice.
+ - id: central
+ run: |
+ token=$(printf '%s:%s' "$CENTRAL_TOKEN_USERNAME" "$CENTRAL_TOKEN_PASSWORD" | base64 -w0)
+ published=$(curl -fsS -H "Authorization: Bearer $token" "https://central.sonatype.com/api/v1/publisher/published?namespace=io.logdash&name=logdash&version=$V" | jq -r '.published')
+ echo "published=$published" >> "$GITHUB_OUTPUT"
+ env:
+ CENTRAL_TOKEN_USERNAME: ${{ secrets.CENTRAL_TOKEN_USERNAME }}
+ CENTRAL_TOKEN_PASSWORD: ${{ secrets.CENTRAL_TOKEN_PASSWORD }}
+ - if: steps.central.outputs.published != 'true'
+ uses: actions/setup-java@v6
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: 'temurin'
-
- - name: Import GPG key
- uses: crazy-max/ghaction-import-gpg@v6
+ cache: maven
+ server-id: central
+ server-username-env-var: CENTRAL_TOKEN_USERNAME
+ server-password-env-var: CENTRAL_TOKEN_PASSWORD
+ # Imports the signing key and gives gpg-agent its passphrase.
+ - if: steps.central.outputs.published != 'true'
+ uses: crazy-max/ghaction-import-gpg@v7
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
-
- - name: Verify GPG import
- run: |
- gpg --list-secret-keys --keyid-format LONG
- echo "✅ GPG key imported successfully"
-
- - name: Configure Maven Settings for Central
- uses: whelk-io/maven-settings-xml-action@v22
- with:
- servers: |
- [
- {
- "id": "central",
- "username": "${env.CENTRAL_TOKEN_USERNAME}",
- "password": "${env.CENTRAL_TOKEN_PASSWORD}"
- }
- ]
-
- - name: Extract Version Info
- id: version
- run: |
- VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
- echo "version=$VERSION" >> $GITHUB_OUTPUT
- echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
-
- # Validate version matches tag
- if [[ "v$VERSION" != "${GITHUB_REF#refs/tags/}" ]]; then
- echo "::error::Version mismatch: POM version ($VERSION) doesn't match tag (${GITHUB_REF#refs/tags/})"
- exit 1
- fi
-
- - name: Check if version exists on Maven Central
- run: |
- VERSION=${{ steps.version.outputs.version }}
- # Check if version exists on Maven Central using search API
- SEARCH_RESULT=$(curl -s "https://search.maven.org/solrsearch/select?q=g:io.logdash+AND+a:logdash+AND+v:$VERSION&rows=1&wt=json")
- COUNT=$(echo "$SEARCH_RESULT" | jq -r '.response.numFound')
-
- if [[ "$COUNT" != "0" ]]; then
- echo "::error::Version $VERSION already exists on Maven Central"
- echo "Cannot redeploy existing version to Maven Central"
- exit 1
- else
- echo "✅ Version $VERSION is available for Maven Central release"
- fi
-
- - name: Build and Deploy to Maven Central
- run: |
- mvn clean deploy -B --no-transfer-progress \
- -Pmaven-central-release \
- -DskipTests=true \
- -Dgpg.keyname="$GPG_KEY_ID"
+ - if: steps.central.outputs.published != 'true'
+ run: mvn -B --no-transfer-progress org.codehaus.mojo:versions-maven-plugin:2.23.0:set -DnewVersion="$V" -DgenerateBackupPoms=false
+ # Signs, uploads to the Central Portal, and waits until it is published.
+ - if: steps.central.outputs.published != 'true'
+ run: mvn clean deploy -B --no-transfer-progress -Pmaven-central-release -DskipTests -Dgpg.keyname="$GPG_KEY_ID"
env:
CENTRAL_TOKEN_USERNAME: ${{ secrets.CENTRAL_TOKEN_USERNAME }}
CENTRAL_TOKEN_PASSWORD: ${{ secrets.CENTRAL_TOKEN_PASSWORD }}
- GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
-
- - name: Verify Maven Central Deployment
- run: |
- VERSION=${{ steps.version.outputs.version }}
- # Check if artifact appears in Central Portal (deployment confirmation)
- if curl -s -f "https://central.sonatype.com/api/internal/browse/component?namespace=io.logdash&name=logdash&version=$VERSION" > /dev/null; then
- echo "✅ Deployment confirmed via Central Portal API"
- else
- echo "⚠️ Not yet visible via Central Portal API (may take time to propagate)"
- fi
-
- - name: Notify Maven Central Success
- run: |
- echo "✅ Successfully deployed logdash:${{ steps.version.outputs.version }} to Maven Central"
- echo "📦 Will be available at: https://central.sonatype.com/artifact/io.logdash/logdash/${{ steps.version.outputs.version }}"
- echo "🌐 Maven Central: https://search.maven.org/artifact/io.logdash/logdash/${{ steps.version.outputs.version }}"
- echo "⏱️ Note: It may take up to 2 hours for the artifact to be searchable via Maven Central"
-
- create-github-release:
- name: Create GitHub Release
- runs-on: ubuntu-latest
- needs: [ github-release, maven-central-release ]
- timeout-minutes: 10
- if: startsWith(github.ref, 'refs/tags/v')
-
- permissions:
- contents: write
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Setup JDK
- uses: actions/setup-java@v4
- with:
- java-version: ${{ env.JAVA_VERSION }}
- distribution: 'temurin'
-
- - name: Extract Version Info
- id: version
- run: |
- VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
- echo "version=$VERSION" >> $GITHUB_OUTPUT
-
- - name: Build Release Artifacts
- run: |
- mvn clean package -B --no-transfer-progress -DskipTests=true
- mkdir -p release-assets
- cp target/logdash-${{ steps.version.outputs.version }}.jar release-assets/
- cp target/logdash-${{ steps.version.outputs.version }}-sources.jar release-assets/
- cp target/logdash-${{ steps.version.outputs.version }}-javadoc.jar release-assets/
-
- # Create checksums
- cd release-assets
- sha256sum *.jar > checksums.sha256
- cd ..
-
- - name: Create GitHub Release
- uses: softprops/action-gh-release@v2
- with:
- files: |
- release-assets/*.jar
- release-assets/checksums.sha256
- generate_release_notes: true
- draft: false
- body: |
- # 🚀 Logdash Java SDK ${{ steps.version.outputs.version }}
-
- Official Java SDK for [Logdash.io](https://logdash.io) – Zero-configuration observability for developers.
-
- ## ✨ Features
-
- - **Zero Configuration**: Start logging and tracking metrics in seconds
- - **Real-time Dashboard**: Cloud-hosted interface with live data updates
- - **Structured Logging**: Multiple log levels with rich context support
- - **Custom Metrics**: Track counters, gauges, and business metrics
- - **Async & Fast**: Non-blocking, production-ready, framework-agnostic
- - **Java 17+ Compatible**: Works with Java 17, 21, 22+
-
- ## 📦 Installation
-
- **Maven Central**
- ```xml
-
- io.logdash
- logdash
- ${{ steps.version.outputs.version }}
-
- ```
-
- **Gradle**
- ```gradle
- implementation 'io.logdash:logdash:${{ steps.version.outputs.version }}'
- ```
-
- ## 🏁 Quick Start
-
- ```java
- var logdash = Logdash.builder()
- .apiKey("your-api-key")
- .build();
-
- logdash.logger().info("Application started");
- logdash.metrics().mutate("app_starts", 1);
- ```
-
- ## ⚙️ Requirements
-
- - Java 17 or higher
- - Internet connection
- - Logdash API key ([get yours](https://logdash.io))
-
- ## 📖 Documentation & Support
-
- - [Full Documentation](https://logdash.io/docs)
- - [Live Demo](https://logdash.io/demo-dashboard)
- - [GitHub Issues](https://github.com/logdash-io/java-sdk/issues)
- - [Discord Community](https://discord.gg/naftPW4Hxe)
- - [Email Support](mailto:contact@logdash.io)
-
- ---
-
- _See below for full release notes and change log._
-
- - name: Deployment Summary
- run: |
- echo "📋 Deployment Status Summary:"
- echo "✅ GitHub Packages: ${{ needs.github-release.result }}"
- echo "✅ Maven Central: ${{ needs.maven-central-release.result }}"
- echo "📦 Version: ${{ steps.version.outputs.version }}"
- echo "🔗 Maven Central: https://central.sonatype.com/artifact/io.logdash/logdash/${{ steps.version.outputs.version }}"
-
- notification:
- name: Notification
- runs-on: ubuntu-latest
- needs: [ validate, test, build, security-scan, github-release, maven-central-release ]
- if: always() && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
-
- steps:
- - name: Check Workflow Status
- run: |
- if [[ "${{ needs.validate.result }}" == "failure" || "${{ needs.test.result }}" == "failure" || "${{ needs.build.result }}" == "failure" ]]; then
- echo "❌ Workflow failed"
- echo "::error::Critical job failed"
- elif [[ "${{ startsWith(github.ref, 'refs/tags/v') }}" == "true" ]]; then
- if [[ "${{ needs.github-release.result }}" == "success" && "${{ needs.maven-central-release.result }}" == "success" ]]; then
- echo "🎉 Release completed successfully!"
- echo "📦 Available on GitHub Packages and Maven Central"
- else
- echo "⚠️ Release partially failed"
- echo "GitHub Release: ${{ needs.github-release.result }}"
- echo "Maven Central: ${{ needs.maven-central-release.result }}"
- fi
- else
- echo "✅ Workflow completed successfully on main branch"
- fi
+ # Last, since it creates the tag that marks the version released.
+ - run: gh release create "v$V" --generate-notes --target "$GITHUB_SHA"
+ env:
+ GH_TOKEN: ${{ github.token }}
+
+ # Installs the version just released from Maven Central and checks that its logs and metrics arrive.
+ check-deployed-package:
+ needs: [ version, release ]
+ uses: ./.github/workflows/check-deployed-package.yml
+ with:
+ version: ${{ needs.version.outputs.next }}
+ secrets:
+ LOGDASH_API_KEY: ${{ secrets.LOGDASH_API_KEY }}
+ LOGDASH_PERSONAL_API_KEY: ${{ secrets.LOGDASH_PERSONAL_API_KEY }}
diff --git a/.github/workflows/develop-snapshots.yml b/.github/workflows/develop-snapshots.yml
deleted file mode 100644
index d80fa41..0000000
--- a/.github/workflows/develop-snapshots.yml
+++ /dev/null
@@ -1,283 +0,0 @@
-name: Develop Branch Snapshots
-
-on:
- push:
- branches: [ develop ]
- schedule:
- - cron: '0 2 * * *'
- workflow_dispatch:
-
-env:
- JAVA_VERSION: '17'
- JAVA_DISTRIBUTION: 'temurin'
-
-jobs:
- validate-develop:
- runs-on: ubuntu-latest
- if: github.ref == 'refs/heads/develop'
- timeout-minutes: 15
- outputs:
- snapshot-version: ${{ steps.version.outputs.snapshot-version }}
-
- steps:
- - name: Checkout develop
- uses: actions/checkout@v4
- with:
- ref: develop
- fetch-depth: 0
-
- - name: Setup JDK ${{ env.JAVA_VERSION }}
- uses: actions/setup-java@v4
- with:
- java-version: ${{ env.JAVA_VERSION }}
- distribution: ${{ env.JAVA_DISTRIBUTION }}
-
- - name: Cache Maven dependencies
- uses: actions/cache@v3
- with:
- path: ~/.m2/repository
- key: ${{ runner.os }}-maven-develop-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-develop-
- ${{ runner.os }}-maven-
-
- - name: Verify snapshot version
- id: version
- run: |
- VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
- if [[ ! $VERSION =~ .*-SNAPSHOT$ ]]; then
- echo "❌ Error: Develop branch must have SNAPSHOT version, found: $VERSION"
- exit 1
- fi
- echo "✅ Snapshot version verified: $VERSION"
- echo "snapshot-version=$VERSION" >> $GITHUB_OUTPUT
-
- - name: Run quick validation
- run: |
- mvn clean validate compile -B --no-transfer-progress \
- -DskipTests=true \
- -Dspotless.check.skip=true
-
- maven-central-snapshot:
- runs-on: ubuntu-latest
- needs: validate-develop
- timeout-minutes: 25
- if: github.ref == 'refs/heads/develop'
-
- steps:
- - name: Checkout develop
- uses: actions/checkout@v4
- with:
- ref: develop
- fetch-depth: 0
-
- - name: Setup JDK ${{ env.JAVA_VERSION }}
- uses: actions/setup-java@v4
- with:
- java-version: ${{ env.JAVA_VERSION }}
- distribution: ${{ env.JAVA_DISTRIBUTION }}
-
- - name: Cache Maven dependencies
- uses: actions/cache@v3
- with:
- path: ~/.m2/repository
- key: ${{ runner.os }}-maven-develop-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-develop-
- ${{ runner.os }}-maven-
-
- - name: Configure Maven Central Snapshots
- uses: whelk-io/maven-settings-xml-action@v22
- with:
- servers: |
- [
- {
- "id": "central",
- "username": "${{ secrets.CENTRAL_TOKEN_USERNAME }}",
- "password": "${{ secrets.CENTRAL_TOKEN_PASSWORD }}"
- }
- ]
-
- - name: Display snapshot version
- run: |
- echo "📦 Deploying snapshot version: ${{ needs.validate-develop.outputs.snapshot-version }}"
-
- - name: Run comprehensive tests
- run: |
- mvn clean verify -B --no-transfer-progress \
- -Dmaven.test.failure.ignore=false \
- -Dfailsafe.rerunFailingTestsCount=2
-
- - name: Deploy to Maven Central Snapshots
- run: |
- mvn deploy -B --no-transfer-progress \
- -Pmaven-central-release \
- -DskipTests=true \
- -Dcentral.autoPublish=true
- env:
- SONATYPE_USERNAME: ${{ secrets.CENTRAL_TOKEN_USERNAME }}
- SONATYPE_PASSWORD: ${{ secrets.CENTRAL_TOKEN_PASSWORD }}
-
- - name: Verify Maven Central snapshot deployment
- run: |
- VERSION="${{ needs.validate-develop.outputs.snapshot-version }}"
- echo "⏳ Waiting for snapshot propagation..."
- sleep 10
-
- # Check if snapshot metadata is available
- METADATA_URL="https://central.sonatype.com/repository/maven-snapshots/io/logdash/logdash/$VERSION/maven-metadata.xml"
- if curl -s -f "$METADATA_URL" > /dev/null; then
- echo "✅ Snapshot metadata confirmed at Maven Central"
- else
- echo "⚠️ Snapshot metadata not yet available (may take time to propagate)"
- fi
-
- - name: Display deployment info
- run: |
- VERSION="${{ needs.validate-develop.outputs.snapshot-version }}"
- echo "✅ Successfully deployed $VERSION to Maven Central Snapshots"
- echo "📦 Available at: https://central.sonatype.com/repository/maven-snapshots/io/logdash/logdash/$VERSION/"
- echo ""
- echo "🔍 Maven dependency:"
- echo ""
- echo " io.logdash"
- echo " logdash"
- echo " $VERSION"
- echo ""
- echo ""
- echo "🔍 Gradle dependency:"
- echo "implementation 'io.logdash:logdash:$VERSION'"
-
- - name: Notify deployment status
- if: failure()
- run: |
- VERSION="${{ needs.validate-develop.outputs.snapshot-version }}"
- echo "❌ Snapshot deployment failed for version $VERSION"
- echo "Check logs above for deployment errors"
-
- github-packages-snapshot:
- runs-on: ubuntu-latest
- needs: validate-develop
- timeout-minutes: 15
- if: github.ref == 'refs/heads/develop'
-
- permissions:
- contents: read
- packages: write
-
- steps:
- - name: Checkout develop
- uses: actions/checkout@v4
- with:
- ref: develop
-
- - name: Setup JDK ${{ env.JAVA_VERSION }}
- uses: actions/setup-java@v4
- with:
- java-version: ${{ env.JAVA_VERSION }}
- distribution: ${{ env.JAVA_DISTRIBUTION }}
-
- - name: Cache Maven dependencies
- uses: actions/cache@v3
- with:
- path: ~/.m2/repository
- key: ${{ runner.os }}-maven-develop-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-develop-
- ${{ runner.os }}-maven-
-
- - name: Configure Maven Settings for GitHub Packages
- uses: whelk-io/maven-settings-xml-action@v22
- with:
- servers: |
- [
- {
- "id": "github",
- "username": "${env.GITHUB_ACTOR}",
- "password": "${env.GITHUB_TOKEN}"
- }
- ]
-
- - name: Deploy to GitHub Packages (Backup)
- run: |
- mvn deploy -B --no-transfer-progress \
- -Pgithub-release \
- -DperformRelease=true \
- -DskipTests=true
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Verify GitHub Packages deployment
- run: |
- VERSION="${{ needs.validate-develop.outputs.snapshot-version }}"
- echo "✅ Backup snapshot deployed to GitHub Packages: $VERSION"
- echo "📦 Available at: https://github.com/logdash-io/java-sdk/packages"
-
- verify-deployments:
- runs-on: ubuntu-latest
- needs: [ maven-central-snapshot, github-packages-snapshot ]
- timeout-minutes: 10
- if: github.ref == 'refs/heads/develop'
-
- steps:
- - name: Final verification
- run: |
- VERSION="${{ needs.validate-develop.outputs.snapshot-version }}"
- echo "🔍 Final verification for snapshot: $VERSION"
-
- # Wait a bit more for propagation
- echo "⏳ Waiting for complete propagation..."
- sleep 10
-
- # Check Maven Central snapshots
- METADATA_URL="https://central.sonatype.com/repository/maven-snapshots/io/logdash/logdash/$VERSION/maven-metadata.xml"
- if curl -s -f "$METADATA_URL" > /dev/null; then
- echo "✅ Maven Central snapshot confirmed and accessible"
- else
- echo "⚠️ Maven Central snapshot metadata not accessible yet"
- fi
-
- echo ""
- echo "📋 Deployment Summary:"
- echo "🏗️ Maven Central Snapshots: ${{ needs.maven-central-snapshot.result }}"
- echo "📦 GitHub Packages: ${{ needs.github-packages-snapshot.result }}"
- echo "🔢 Version: $VERSION"
- echo "🌐 Repository: https://central.sonatype.com/repository/maven-snapshots/"
-
- notification:
- runs-on: ubuntu-latest
- needs: [ validate-develop, maven-central-snapshot, github-packages-snapshot, verify-deployments ]
- if: always() && github.ref == 'refs/heads/develop'
-
- steps:
- - name: Workflow status summary
- run: |
- VERSION="${{ needs.validate-develop.outputs.snapshot-version }}"
-
- echo "📊 Develop Branch Snapshot Workflow Summary"
- echo "============================================="
- echo "🔢 Version: $VERSION"
- echo "📅 Triggered: ${{ github.event_name }}"
- echo ""
- echo "Job Results:"
- echo "✓ Validation: ${{ needs.validate-develop.result }}"
- echo "✓ Maven Central: ${{ needs.maven-central-snapshot.result }}"
- echo "✓ GitHub Packages: ${{ needs.github-packages-snapshot.result }}"
- echo "✓ Verification: ${{ needs.verify-deployments.result }}"
- echo ""
-
- # Check overall success
- if [[ "${{ needs.validate-develop.result }}" == "success" &&
- "${{ needs.maven-central-snapshot.result }}" == "success" &&
- "${{ needs.github-packages-snapshot.result }}" == "success" ]]; then
- echo "🎉 All snapshot deployments completed successfully!"
- echo "📦 $VERSION is now available for testing"
- else
- echo "⚠️ Some deployments may have failed. Check individual job results above."
- fi
-
- echo ""
- echo "🔗 Quick Access:"
- echo "- Maven Central: https://central.sonatype.com/repository/maven-snapshots/io/logdash/logdash/$VERSION/"
- echo "- GitHub Packages: https://github.com/logdash-io/java-sdk/packages"
- echo "- Workflow: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
\ No newline at end of file
diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml
new file mode 100644
index 0000000..74fcf0b
--- /dev/null
+++ b/.github/workflows/pr-title.yml
@@ -0,0 +1,20 @@
+name: PR title
+
+# Squash merges use the PR title as the commit subject, and scripts/version.ts reads it to pick the next version.
+on:
+ pull_request:
+ types: [opened, edited, reopened, synchronize]
+
+permissions: {}
+
+jobs:
+ conventional:
+ runs-on: ubuntu-latest
+ steps:
+ - env:
+ TITLE: ${{ github.event.pull_request.title }}
+ run: |
+ printf '%s' "$TITLE" | grep -qE '^(feat|fix|perf|refactor|docs|test|build|ci|chore|style|revert)(\(.+\))?!?: .+' || {
+ echo "::error::PR title \"$TITLE\" is not a Conventional Commit, e.g. \"feat(metrics): add histograms\" or \"fix(transport): retry after a 429\". feat releases a minor, fix/perf a patch, ! a major; other types do not release."
+ exit 1
+ }
diff --git a/README.md b/README.md
index fb651b1..d51173c 100644
--- a/README.md
+++ b/README.md
@@ -71,7 +71,7 @@ Then use in your project:
io.logdash
logdash
- 0.2.0
+ 0.0.0-SNAPSHOT
```
diff --git a/check-deployed-package/Check.java b/check-deployed-package/Check.java
index 48e50c3..f642e3f 100644
--- a/check-deployed-package/Check.java
+++ b/check-deployed-package/Check.java
@@ -2,28 +2,28 @@
import io.logdash.sdk.Logdash;
-
+/**
+ * Sends a log of each level and a metric with the SDK as published, for run.sh to read back.
+ */
public class Check {
public static void main(String[] args) {
- System.out.println("=== LogDash Java SDK Demo ===");
-
- // Get package version (would need to be handled differently in a real scenario)
- System.out.println("Using logdash package version: " + getLogdashVersion());
- System.out.println();
-
- String apiKey = System.getenv("LOGDASH_API_KEY");
String logsSeed = System.getenv().getOrDefault("LOGS_SEED", "default");
- String metricsSeed = System.getenv().getOrDefault("METRICS_SEED", "1");
-
- System.out.println("Using API Key: " + apiKey);
- System.out.println("Using Logs Seed: " + logsSeed);
- System.out.println("Using Metrics Seed: " + metricsSeed);
-
- try (Logdash logdash = Logdash.create(apiKey)) {
+ int metricsSeed = Integer.parseInt(System.getenv().getOrDefault("METRICS_SEED", "1"));
+
+ System.out.println("=== Logdash Java SDK check ===");
+ System.out.println("Using logdash " + System.getenv("LOGDASH_VERSION"));
+ System.out.println("Using logs seed: " + logsSeed);
+ System.out.println("Using metrics seed: " + metricsSeed);
+
+ try (Logdash logdash =
+ Logdash.builder()
+ .apiKey(System.getenv("LOGDASH_API_KEY"))
+ .baseUrl(System.getenv().getOrDefault("LOGDASH_API_URL", "https://api.logdash.io"))
+ .app("java-sdk")
+ .build()) {
var logger = logdash.logger();
var metrics = logdash.metrics();
- // Log some messages with seed appended
logger.info("This is an info log " + logsSeed);
logger.error("This is an error log " + logsSeed);
logger.warn("This is a warning log " + logsSeed);
@@ -33,25 +33,10 @@ public static void main(String[] args) {
logger.info("This is an info log " + logsSeed);
logger.verbose("This is a verbose log " + logsSeed);
- // Set and mutate metrics with seed
- int seedValue = Integer.parseInt(metricsSeed);
- metrics.set("users", seedValue);
- metrics.mutate("users", 1);
-
- // Wait to ensure data is sent
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- }
-
- private static String getLogdashVersion() {
- try {
- return Check.class.getPackage().getImplementationVersion();
- } catch (Exception e) {
- return "unknown";
- }
+ metrics.set("users_java", metricsSeed);
+ // The mutate adds to the set, so the set must arrive first
+ logdash.flush();
+ metrics.mutate("users_java", 1);
+ } // close sends what is still queued
}
}
diff --git a/check-deployed-package/Dockerfile b/check-deployed-package/Dockerfile
index 32537e5..27987e7 100644
--- a/check-deployed-package/Dockerfile
+++ b/check-deployed-package/Dockerfile
@@ -1,25 +1,14 @@
-FROM eclipse-temurin:17-jdk
+FROM maven:3.9-eclipse-temurin-17
WORKDIR /app
-# Install Maven
-RUN apt-get update && apt-get install -y maven && rm -rf /var/lib/apt/lists/*
+# The SDK version to install from Maven Central, into this image's empty local repository
+ARG LOGDASH_VERSION
+ENV LOGDASH_VERSION=${LOGDASH_VERSION}
-# Copy project files
COPY check-deployed-package/pom.xml .
-COPY check-deployed-package/Check.java src/main/java/com/logdash/check/Check.java
+COPY check-deployed-package/Check.java src/main/java/io/logdash/check/Check.java
-# Download dependencies and compile
-RUN mvn dependency:resolve compile -B --no-transfer-progress
+RUN mvn compile -B --no-transfer-progress -Dlogdash.version="$LOGDASH_VERSION"
-# Add environment variable validation
-ENV LOGDASH_API_KEY=""
-ENV LOGS_SEED=""
-ENV METRICS_SEED=""
-
-# Run the application with environment validation
-CMD if [ -z "$LOGDASH_API_KEY" ]; then \
- echo "Error: LOGDASH_API_KEY environment variable is required"; \
- exit 1; \
- fi; \
- mvn exec:java -B --no-transfer-progress
+CMD ["sh", "-c", "exec mvn exec:java -B --no-transfer-progress -q -Dlogdash.version=\"$LOGDASH_VERSION\""]
diff --git a/check-deployed-package/README.md b/check-deployed-package/README.md
index 4941f66..76698b3 100644
--- a/check-deployed-package/README.md
+++ b/check-deployed-package/README.md
@@ -1,8 +1,14 @@
-# LogDash Java SDK Demo
+# Logdash Java SDK check
-Use command below to test if the published SDK works:
+Checks the SDK as Maven Central serves it: installs it in a clean container, sends logs and metrics with it, and reads them back.
+CI runs it after each release.
```
-LOGDASH_API_KEY= ./check-deployed-package/run.sh
+LOGDASH_API_KEY= LOGDASH_PERSONAL_API_KEY= ./check-deployed-package/run.sh
```
+`LOGDASH_API_KEY` is the ingest key of the "SDK smoke tests" domain, from its Settings page.
+The check sends as the app `java-sdk`, so each SDK shows up as its own app on that domain.
+`LOGDASH_PERSONAL_API_KEY` is an `ldp_` personal API key with `logs:read` and `metrics:read`, restricted to that domain.
+`LOGDASH_VERSION` picks the version to check, the latest release by default.
+`LOGDASH_API_URL` picks the API, `https://api.logdash.io` by default.
diff --git a/check-deployed-package/pom.xml b/check-deployed-package/pom.xml
index 9bed4ed..aa6335b 100644
--- a/check-deployed-package/pom.xml
+++ b/check-deployed-package/pom.xml
@@ -4,7 +4,7 @@
io.logdash
check
- 0.2.0
+ 0.0.0-SNAPSHOT
17
@@ -18,24 +18,10 @@
io.logdash
logdash
- 0.2.0
+ ${logdash.version}
-
-
-
- true
-
-
- true
-
- github
- GitHub Packages
- https://maven.pkg.github.com/logdash-io/java-sdk
-
-
-
diff --git a/check-deployed-package/run.sh b/check-deployed-package/run.sh
index 9bb06d7..92cd5fc 100755
--- a/check-deployed-package/run.sh
+++ b/check-deployed-package/run.sh
@@ -1,126 +1,97 @@
#!/bin/sh
-set -e
-
-# Generate random 5-character seed
-LOGS_SEED=$(openssl rand -hex 2 | cut -c1-5)
-echo "Generated seed: $LOGS_SEED"
-
-# Generate random metrics seed (1-1,000,000)
-METRICS_SEED=$(awk 'BEGIN{srand(); print int(rand()*1000000)+1}')
-echo "Generated metrics seed: $METRICS_SEED"
-
-echo "Building LogDash Java demo Docker image (using published package)..."
-docker build --no-cache \
- -t logdash-java-demo \
- -f check-deployed-package/Dockerfile .
-
-echo
-echo "Running LogDash Java demo..."
-echo
-
-# Run in non-interactive mode which works everywhere
-docker run --rm \
- -e LOGDASH_API_KEY="${LOGDASH_API_KEY}" \
- -e LOGS_SEED="${LOGS_SEED}" \
- -e METRICS_SEED="${METRICS_SEED}" \
- logdash-java-demo
-
-echo
-echo "Demo completed!"
-
-echo
-echo "Authenticating with LogDash API..."
-
-# Authenticate with API using the API key
-AUTH_RESPONSE=$(curl -s -X 'POST' \
- 'https://api.logdash.io/auth/api-key' \
- -H 'accept: application/json' \
- -H 'Content-Type: application/json' \
- -d "{
- \"apiKey\": \"${LOGDASH_API_KEY}\"
-}")
-
-# Extract token and projectId from response
-TOKEN=$(echo "$AUTH_RESPONSE" | grep -o '"token":"[^"]*"' | sed 's/"token":"\(.*\)"/\1/')
-PROJECT_ID=$(echo "$AUTH_RESPONSE" | grep -o '"projectId":"[^"]*"' | sed 's/"projectId":"\(.*\)"/\1/')
-
-if [ -z "$TOKEN" ] || [ -z "$PROJECT_ID" ]; then
- echo "Error: Failed to authenticate with LogDash API"
- echo "Response: $AUTH_RESPONSE"
+# Checks the SDK as Maven Central serves it: installs it in a clean container, sends logs and metrics
+# with it, and reads them back.
+# LOGDASH_API_KEY: the ingest key of the "SDK smoke tests" domain, which sends as the app java-sdk.
+# LOGDASH_PERSONAL_API_KEY: an ldp_ personal API key with logs:read and metrics:read, restricted to
+# that one domain, which reads back.
+# LOGDASH_VERSION: the version to check; empty checks the latest release.
+# LOGDASH_API_URL: the API both halves talk to, https://api.logdash.io by default.
+set -eu
+
+: "${LOGDASH_API_KEY:?must be the ingest key of the smoke-test domain}"
+: "${LOGDASH_PERSONAL_API_KEY:?must be a personal API key that reads the smoke-test domain}"
+API=${LOGDASH_API_URL:-https://api.logdash.io}
+CENTRAL=https://repo.maven.apache.org/maven2/io/logdash/logdash
+VERSION=${LOGDASH_VERSION:-$(curl -fsS "$CENTRAL/maven-metadata.xml" | sed -n 's:.*\(.*\).*:\1:p')}
+VERSION=${VERSION#v}
+if [ -z "$VERSION" ]; then
+ echo "Error: no version to check, and Maven Central names no latest release"
exit 1
fi
-echo "Authentication successful. Project ID: $PROJECT_ID"
-
-echo
-echo "Fetching logs from LogDash API..."
-
-# Fetch logs from the API
-LOGS_RESPONSE=$(curl -s -X 'GET' \
- "https://api.logdash.io/projects/${PROJECT_ID}/logs?limit=10" \
- -H 'accept: application/json' \
- -H "Authorization: Bearer ${TOKEN}")
-
-echo "Logs fetched successfully"
-
-echo
-echo "Validating log messages..."
-
-# Expected log messages with seed
-EXPECTED_MESSAGES="This is an info log ${LOGS_SEED}
-This is an error log ${LOGS_SEED}
-This is a warning log ${LOGS_SEED}
-This is a debug log ${LOGS_SEED}
-This is a http log ${LOGS_SEED}
-This is a silly log ${LOGS_SEED}
-This is an info log ${LOGS_SEED}
-This is a verbose log ${LOGS_SEED}"
-
-# Check if all expected messages are present in the logs
-echo "$EXPECTED_MESSAGES" | while IFS= read -r expected_msg; do
- if ! echo "$LOGS_RESPONSE" | grep -q "$expected_msg"; then
- echo "Error: Expected log message not found: '$expected_msg'"
- echo "Logs response: $LOGS_RESPONSE"
+# A release reaches Maven Central some minutes after the Central Portal publishes it.
+echo "Waiting until Maven Central serves logdash $VERSION..."
+tries=0
+until curl -fsIo /dev/null "$CENTRAL/$VERSION/logdash-$VERSION.pom" && curl -fsIo /dev/null "$CENTRAL/$VERSION/logdash-$VERSION.jar"; do
+ tries=$((tries + 1))
+ if [ "$tries" -ge 120 ]; then
+ echo "Error: Maven Central does not serve logdash $VERSION after an hour"
exit 1
fi
- echo "✓ Found: '$expected_msg'"
+ sleep 30
done
-echo
-echo "Fetching metrics from LogDash API..."
-
-# Fetch metrics from the API
-METRICS_RESPONSE=$(curl -s -X 'GET' \
- "https://api.logdash.io/projects/${PROJECT_ID}/metrics" \
- -H 'accept: application/json' \
- -H "Authorization: Bearer ${TOKEN}")
+LOGS_SEED=$(openssl rand -hex 4)
+METRICS_SEED=$(awk 'BEGIN { srand(); print int(rand() * 1000000) + 1 }')
+echo "Logs seed: $LOGS_SEED, metrics seed: $METRICS_SEED"
-echo "Metrics fetched successfully"
+docker build --no-cache --build-arg LOGDASH_VERSION="$VERSION" -t logdash-java-check -f check-deployed-package/Dockerfile .
+docker run --rm -e LOGDASH_API_KEY -e LOGDASH_API_URL="$API" -e LOGS_SEED="$LOGS_SEED" -e METRICS_SEED="$METRICS_SEED" logdash-java-check
-echo
-echo "Validating metrics..."
+# GETs an API path with the personal key: prints the response, and fails on an HTTP error.
+get() {
+ curl -sS --fail-with-body -H "Authorization: Bearer $LOGDASH_PERSONAL_API_KEY" "$API$1"
+}
-# Expected users metric value (metrics_seed + 1)
-EXPECTED_USERS_VALUE=$((METRICS_SEED + 1))
-
-# Check if users metric exists with correct value
-if ! echo "$METRICS_RESPONSE" | grep -q '"name":"users"'; then
- echo "Error: Users metric not found"
- echo "Metrics response: $METRICS_RESPONSE"
+WHOAMI=$(get /personal-api-keys/whoami) || {
+ echo "Error: whoami rejects LOGDASH_PERSONAL_API_KEY: $WHOAMI"
exit 1
-fi
-
-# Extract the value of the users metric and check if it matches expected value
-USERS_VALUE=$(echo "$METRICS_RESPONSE" | sed 's/},{/}\n{/g' | grep '"name":"users"' | grep -o '"value":[0-9]*' | sed 's/"value"://')
-
-if [ "$USERS_VALUE" != "$EXPECTED_USERS_VALUE" ]; then
- echo "Error: Users metric value mismatch. Expected: $EXPECTED_USERS_VALUE, Found: $USERS_VALUE"
- echo "Metrics response: $METRICS_RESPONSE"
+}
+DOMAIN_ID=$(printf '%s' "$WHOAMI" | jq -r 'if .access.kind == "clusters" and (.access.ids | length) == 1 then .access.ids[0] else empty end')
+if [ -z "$DOMAIN_ID" ]; then
+ echo "Error: LOGDASH_PERSONAL_API_KEY must be restricted to the one smoke-test domain: $WHOAMI"
exit 1
fi
-
-echo "✓ Found users metric with correct value: $USERS_VALUE"
-
-echo
-echo "All expected log messages and metrics found successfully!"
-echo "Validation completed!"
\ No newline at end of file
+echo "Reading back from domain $DOMAIN_ID"
+
+EXPECTED_LOGS=$(jq -n --arg seed "$LOGS_SEED" '[
+ ["info", "This is an info log \($seed)"],
+ ["error", "This is an error log \($seed)"],
+ ["warning", "This is a warning log \($seed)"],
+ ["debug", "This is a debug log \($seed)"],
+ ["http", "This is a http log \($seed)"],
+ ["silly", "This is a silly log \($seed)"],
+ ["verbose", "This is a verbose log \($seed)"]
+]')
+EXPECTED_USERS=$((METRICS_SEED + 1))
+
+# Ingestion is asynchronous, so each read-back retries for a minute.
+LOGS='' MISSING='' tries=0
+until
+ LOGS=$(get "/clusters/$DOMAIN_ID/logs?apps=java-sdk&limit=100&searchString=$LOGS_SEED") &&
+ MISSING=$(printf '%s' "$LOGS" | jq -r --argjson want "$EXPECTED_LOGS" '$want - [.[] | [.level, .message]] | .[] | join(": ")') &&
+ [ -z "$MISSING" ]
+do
+ tries=$((tries + 1))
+ if [ "$tries" -ge 12 ]; then
+ printf 'Error: logs not found:\n%s\nResponse: %s\n' "$MISSING" "$LOGS"
+ exit 1
+ fi
+ sleep 5
+done
+echo "✓ Found a log of each of the 7 levels"
+
+METRICS='' USERS='' tries=0
+until
+ METRICS=$(get "/clusters/$DOMAIN_ID/metrics") &&
+ USERS=$(printf '%s' "$METRICS" | jq -r '.[] | select(.app == "java-sdk" and .name == "users_java") | .value') &&
+ [ "$USERS" = "$EXPECTED_USERS" ]
+do
+ tries=$((tries + 1))
+ if [ "$tries" -ge 12 ]; then
+ echo "Error: metric users_java is ${USERS:-missing}, expected $EXPECTED_USERS. Response: $METRICS"
+ exit 1
+ fi
+ sleep 5
+done
+echo "✓ Found metric users_java = $USERS"
diff --git a/examples/example-simple-java/pom.xml b/examples/example-simple-java/pom.xml
index ff4b4f7..4908fb2 100644
--- a/examples/example-simple-java/pom.xml
+++ b/examples/example-simple-java/pom.xml
@@ -58,25 +58,4 @@
-
-
-
- snapshot-repo
-
-
- logdash.version
- *-SNAPSHOT
-
-
-
-
-
- true
-
- github-snapshots
- https://maven.pkg.github.com/logdash-io/java-sdk
-
-
-
-
diff --git a/pom.xml b/pom.xml
index dbc609e..7e1a9a9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,8 @@
io.logdash
logdash
- 0.2.0
+
+ 0.0.0-SNAPSHOT
jar
Logdash Java SDK
@@ -48,13 +49,14 @@
3.27.3
3.13.0
2.0.17
- 2.19.0
+ 2.22.4
3.14.0
3.5.3
3.5.3
0.8.13
+ 3.5.1
3.3.1
3.11.2
4.9.3.0
@@ -66,6 +68,19 @@
0.7.0
+
+
+
+
+ com.fasterxml.jackson
+ jackson-bom
+ ${jackson.version}
+ pom
+ import
+
+
+
+
@@ -76,22 +91,18 @@
com.fasterxml.jackson.core
jackson-core
- ${jackson.version}
com.fasterxml.jackson.core
jackson-databind
- ${jackson.version}
com.fasterxml.jackson.core
jackson-annotations
- ${jackson.version}
com.fasterxml.jackson.datatype
jackson-datatype-jsr310
- ${jackson.version}
@@ -365,6 +376,20 @@
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ ${maven-jar-plugin.version}
+
+
+
+ true
+
+
+
+
+
org.apache.maven.plugins
@@ -502,43 +527,6 @@
-
-
- github-release
-
-
- performRelease
- true
-
-
-
-
- github
- GitHub Packages
- https://maven.pkg.github.com/logdash-io/java-sdk
-
-
- github
- GitHub Packages
- https://maven.pkg.github.com/logdash-io/java-sdk
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-deploy-plugin
- ${maven-deploy-plugin.version}
-
- true
- false
-
-
-
-
-
-
maven-central-release
diff --git a/scripts/dev-cycle.sh b/scripts/dev-cycle.sh
index 4322e7f..1131043 100755
--- a/scripts/dev-cycle.sh
+++ b/scripts/dev-cycle.sh
@@ -6,6 +6,6 @@ mvn clean install -DskipTests
echo "🚀 Testing SpringBoot example with local snapshot..."
cd examples/example-springboot
-mvn clean spring-boot:run -Plocal-dev
+mvn clean spring-boot:run -Plocal-dev -Dlogdash-sdk.version=0.0.0-SNAPSHOT
echo "✅ Development cycle completed!"
diff --git a/scripts/version.test.ts b/scripts/version.test.ts
new file mode 100644
index 0000000..316cade
--- /dev/null
+++ b/scripts/version.test.ts
@@ -0,0 +1,16 @@
+import { test } from 'node:test'
+import assert from 'node:assert/strict'
+import { nextVersion } from './version.ts'
+
+test('the next version follows the Conventional Commits since the last release', () => {
+ assert.equal(nextVersion(null, []), '0.1.0', 'first release')
+ assert.equal(nextVersion('0.1.0', []), null, 'nothing merged')
+ assert.equal(nextVersion('0.1.0', ['chore: deps', 'ci(release): cache', 'docs: readme']), null, 'nothing users get')
+ assert.equal(nextVersion('0.1.3', ['fix: crash on #', 'chore: x']), '0.1.4')
+ assert.equal(nextVersion('0.1.3', ['perf(export): faster']), '0.1.4')
+ assert.equal(nextVersion('0.1.3', ['fix: a', 'feat(timeline): b']), '0.2.0')
+ assert.equal(nextVersion('0.9.3', ['feat!: new format']), '1.0.0')
+ assert.equal(nextVersion('0.9.3', ['refactor(projects): x\n\nBREAKING CHANGE: old bundles no longer open']), '1.0.0')
+ assert.equal(nextVersion('1.2.3', ['Feature: no prefix', 'fixed: typo', 'feat : spaced', 'featx: y']), null, 'only exact types count')
+ assert.equal(nextVersion('1.2.3', ['chore: x\n\n* feat: from a squashed commit list']), null, 'only subjects count')
+})
diff --git a/scripts/version.ts b/scripts/version.ts
new file mode 100644
index 0000000..7c9989f
--- /dev/null
+++ b/scripts/version.ts
@@ -0,0 +1,26 @@
+// `node scripts/version.ts`: the version the commits since the last release call for, from their
+// Conventional Commit subjects, or nothing when none of them changes the app. CI runs it after each
+// merge to main and releases what it prints. Releases are tagged v; the tags are the
+// source of truth, pom.xml's version is a placeholder CI overwrites before packaging.
+import { execFileSync } from 'node:child_process'
+
+/** The next version after `last` (null before the first release), given the commit messages since it. */
+export function nextVersion(last: string | null, messages: string[]): string | null {
+ if (!last) return '0.1.0'
+ const subjects = messages.map((m) => m.split('\n')[0])
+ const [major, minor, patch] = last.split('.').map(Number)
+ if (subjects.some((s) => /^\w+(\(.+\))?!:/.test(s)) || messages.some((m) => /^BREAKING[ -]CHANGE:/m.test(m))) return `${major + 1}.0.0`
+ if (subjects.some((s) => /^feat(\(.+\))?:/.test(s))) return `${major}.${minor + 1}.0`
+ if (subjects.some((s) => /^(fix|perf)(\(.+\))?:/.test(s))) return `${major}.${minor}.${patch + 1}`
+ return null
+}
+
+if (import.meta.main) {
+ const git = (...args: string[]) => execFileSync('git', args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] })
+ let tag: string | null = null
+ try {
+ tag = git('describe', '--tags', '--abbrev=0', '--match', 'v[0-9]*').trim()
+ } catch {} // no release yet
+ const messages = tag ? git('log', '--format=%B%x00', `${tag}..HEAD`).split('\0').map((m) => m.trim()).filter(Boolean) : []
+ console.log(nextVersion(tag?.slice(1) ?? null, messages) ?? '')
+}
diff --git a/src/main/java/io/logdash/sdk/transport/HttpTransport.java b/src/main/java/io/logdash/sdk/transport/HttpTransport.java
index ed5d0e7..8d4cf30 100644
--- a/src/main/java/io/logdash/sdk/transport/HttpTransport.java
+++ b/src/main/java/io/logdash/sdk/transport/HttpTransport.java
@@ -14,6 +14,7 @@
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.*;
@@ -42,7 +43,11 @@ public final class HttpTransport implements LogdashTransport, AutoCloseable {
private static final String EVENTS_ENDPOINT = "/events";
private static final String API_KEY_HEADER = "project-api-key";
- private static final String USER_AGENT = "logdash-java-sdk/0.2.0";
+ // The jar's Implementation-Version, the version CI releases; null when not run from the jar
+ private static final String USER_AGENT =
+ "logdash-java-sdk/"
+ + Objects.requireNonNullElse(
+ HttpTransport.class.getPackage().getImplementationVersion(), "unknown");
private static final String CONTENT_TYPE = "application/json";
private final LogdashConfig config;
diff --git a/src/main/java/io/logdash/sdk/util/JsonSerializer.java b/src/main/java/io/logdash/sdk/util/JsonSerializer.java
index ec2de4e..01fbefc 100644
--- a/src/main/java/io/logdash/sdk/util/JsonSerializer.java
+++ b/src/main/java/io/logdash/sdk/util/JsonSerializer.java
@@ -52,7 +52,8 @@ private static ObjectMapper createObjectMapper() {
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
- .serializationInclusion(JsonInclude.Include.NON_NULL)
+ .defaultPropertyInclusion(
+ JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL))
.build();
}
diff --git a/src/test/java/io/logdash/sdk/transport/HttpTransportTest.java b/src/test/java/io/logdash/sdk/transport/HttpTransportTest.java
index 1917b2e..2328b87 100644
--- a/src/test/java/io/logdash/sdk/transport/HttpTransportTest.java
+++ b/src/test/java/io/logdash/sdk/transport/HttpTransportTest.java
@@ -84,7 +84,7 @@ void should_successfully_send_log_entry() {
postRequestedFor(urlEqualTo("/logs"))
.withHeader("Content-Type", equalTo("application/json"))
.withHeader("project-api-key", equalTo("test-api-key"))
- .withHeader("User-Agent", equalTo("logdash-java-sdk/0.2.0")));
+ .withHeader("User-Agent", matching("logdash-java-sdk/.+")));
}
@Test
@@ -107,7 +107,7 @@ void should_successfully_send_metric_entry() {
putRequestedFor(urlEqualTo("/metrics"))
.withHeader("Content-Type", equalTo("application/json"))
.withHeader("project-api-key", equalTo("test-api-key"))
- .withHeader("User-Agent", equalTo("logdash-java-sdk/0.2.0")));
+ .withHeader("User-Agent", matching("logdash-java-sdk/.+")));
}
@ParameterizedTest