diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33b8b9f..79f6326 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,10 +2,10 @@ name: CI/CD Pipeline on: push: - branches: [ main ] + branches: [ main, dev ] tags: [ 'v*' ] pull_request: - branches: [ main ] + branches: [ main, dev ] permissions: contents: write @@ -263,12 +263,9 @@ jobs: exit 1 fi - - name: Check if version exists + - name: Check if version exists in GitHub Packages run: | - VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - + 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" @@ -346,6 +343,21 @@ jobs: 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 \ @@ -356,12 +368,24 @@ jobs: 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 @@ -469,6 +493,14 @@ jobs: _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 diff --git a/.github/workflows/develop-snapshots.yml b/.github/workflows/develop-snapshots.yml new file mode 100644 index 0000000..d80fa41 --- /dev/null +++ b/.github/workflows/develop-snapshots.yml @@ -0,0 +1,283 @@ +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/README.md b/README.md index 65372e7..af05125 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,19 @@ # Logdash Java SDK [![GitHub Release](https://img.shields.io/github/v/release/logdash-io/java-sdk)](https://github.com/logdash-io/java-sdk/releases) +[![Maven Central](https://img.shields.io/maven-central/v/io.logdash/logdash)](https://central.sonatype.com/artifact/io.logdash/logdash) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Java Version](https://img.shields.io/badge/Java-17+-blue.svg)](https://openjdk.java.net/projects/jdk/17/) [![CI/CD](https://github.com/logdash-io/java-sdk/workflows/CI/CD%20Pipeline/badge.svg)](https://github.com/logdash-io/java-sdk/actions) +[![Coverage](https://img.shields.io/codecov/c/github/logdash-io/java-sdk)](https://codecov.io/gh/logdash-io/java-sdk) -Official Java SDK for [Logdash.io](https://logdash.io/) - Zero-configuration observability platform designed for developers working on side projects and prototypes. +> **Official Java SDK for [Logdash.io](https://logdash.io/) - Zero-configuration observability platform designed for developers working on side projects and prototypes.** ## Why Logdash? -Most observability solutions feel overwhelming for hobby projects. Logdash provides instant logging and real-time -metrics without complex configurations. Just add the SDK and start monitoring your application immediately. +Most observability solutions feel overwhelming for small projects and prototypes. Logdash provides **instant logging and real-time metrics** without complex configurations. Just add the SDK and start monitoring your application immediately. -## Features +## Key Features - **🚀 Zero Configuration**: Start logging and tracking metrics in seconds - **📊 Real-time Dashboard**: Cloud-hosted interface with live data updates @@ -23,41 +24,39 @@ metrics without complex configurations. Just add the SDK and start monitoring yo - **🔧 Framework Agnostic**: Works with Spring Boot, Quarkus, Micronaut, or standalone apps - **☕ Java 17+ Compatible**: Supports Java 17, 21, and all newer versions -## Quick Start - -### Installation +## Pre-requisites -**Maven Central** +Setup your free project in less than 2 minutes at [logdash.io](https://logdash.io/) -Add the dependency to your project: +## Installation -**Maven:** +### Maven Central ```xml io.logdash logdash - 0.1.3 + 0.2.0 ``` -**Gradle:** +### Gradle -```gradle +```groovy dependencies { - implementation 'io.logdash:logdash:0.1.3' + implementation 'io.logdash:logdash:0.2.0' } ``` -**Gradle (Kotlin DSL):** +### Gradle (Kotlin DSL) ```kotlin dependencies { - implementation("io.logdash:logdash:0.1.3") + implementation("io.logdash:logdash:0.2.0") } ``` -**Local Installation** +### Local Installation ```bash # Clone and install locally @@ -72,10 +71,12 @@ Then use in your project: io.logdash logdash - 0.1.3 + 0.2.0 ``` +## Quick Start + ### Basic Usage ```java @@ -270,10 +271,10 @@ Track business and technical metrics to monitor application performance: var metrics = logdash.metrics(); // Counters - track events and occurrences -metrics.mutate("page_views",1); -metrics.mutate("api_requests",5); -metrics.mutate("response_time_ms",-100); -metrics.mutate("available_licenses",-1); +metrics.mutate("page_views", 1); +metrics.mutate("api_requests", 5); +metrics.mutate("response_time_ms", -100); +metrics.mutate("available_licenses", -1); // Gauges - track current values metrics.set("active_users", 1_250); @@ -281,6 +282,14 @@ metrics.set("memory_usage_mb", 512.5); metrics.set("queue_size", 0); ``` +## View Your Data + +To see the logs or metrics, go to your project dashboard at [logdash.io](https://logdash.io/app/clusters) + +![Logs Dashboard](docs/images/logs.png) + +![Metrics Dashboard](docs/images/delta.png) + ## Configuration ### Development Configuration @@ -306,9 +315,11 @@ Logdash logdash = Logdash.builder() .build(); ``` +## Configuration + ### All Configuration Options -| Option | Default | Description | +| Parameter | Default | Description | |-------------------------|--------------------------|----------------------------------| | `apiKey` | `null` | Your Logdash API key (required) | | `baseUrl` | `https://api.logdash.io` | Logdash API endpoint | @@ -371,7 +382,7 @@ Check out the [`examples/`](./examples) directory for a complete sample applicat - **Java 17 or higher** (tested on Java 17, 21, 22) - **Internet connection** for sending data to Logdash -- **Valid API key** from [Logdash.io](https://logdash.io) +- **Valid API key** from [logdash.io](https://logdash.io) ## Contributing @@ -383,7 +394,6 @@ We welcome contributions! Here's how to get started: git clone https://github.com/logdash-io/java-sdk.git cd java-sdk mvn clean compile -mvn test ``` ### Running Tests @@ -399,9 +409,24 @@ mvn failsafe:integration-test mvn clean verify ``` +### GitFlow Workflow + +```bash +# Start new feature +git checkout dev && git pull origin dev +git checkout -b feat/awesome-feature + +# Development and testing +mvn clean verify +git add . && git commit -m "feat: add awesome feature" +git push origin feat/awesome-feature + +# Create pull request to dev branch +``` + ### Code Quality -- Follow existing code style (checkstyle configuration included) +- Follow existing code style - Ensure all tests pass - Add tests for new features - Update documentation as needed diff --git a/check-deployed-package/Check.java b/check-deployed-package/Check.java index 4b2229b..48e50c3 100644 --- a/check-deployed-package/Check.java +++ b/check-deployed-package/Check.java @@ -2,28 +2,27 @@ import io.logdash.sdk.Logdash; -import java.util.Map; 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)) { 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); @@ -33,7 +32,7 @@ public static void main(String[] args) { logger.silly("This is a silly log " + logsSeed); 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); @@ -47,7 +46,7 @@ public static void main(String[] args) { } } } - + private static String getLogdashVersion() { try { return Check.class.getPackage().getImplementationVersion(); @@ -55,4 +54,4 @@ private static String getLogdashVersion() { return "unknown"; } } -} \ No newline at end of file +} diff --git a/check-deployed-package/pom.xml b/check-deployed-package/pom.xml index 5c00c13..9bed4ed 100644 --- a/check-deployed-package/pom.xml +++ b/check-deployed-package/pom.xml @@ -1,13 +1,16 @@ 4.0.0 + io.logdash check - 1.0.0 + 0.2.0 - 17 - 17 + 17 + ${java.version} + ${java.version} + ${java.version} UTF-8 @@ -15,7 +18,7 @@ io.logdash logdash - 0.1.3 + 0.2.0 @@ -38,16 +41,22 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 - 17 - 17 + ${java.version} + + -parameters + -Xlint:unchecked + -Xlint:deprecation + -Werror + + org.codehaus.mojo exec-maven-plugin - 3.1.0 + 3.1.1 io.logdash.check.Check diff --git a/docs/images/delta.png b/docs/images/delta.png new file mode 100644 index 0000000..b311d3d Binary files /dev/null and b/docs/images/delta.png differ diff --git a/docs/images/logs.png b/docs/images/logs.png new file mode 100644 index 0000000..62f6872 Binary files /dev/null and b/docs/images/logs.png differ diff --git a/examples/example-simple-java/pom.xml b/examples/example-simple-java/pom.xml index ad72762..ff4b4f7 100644 --- a/examples/example-simple-java/pom.xml +++ b/examples/example-simple-java/pom.xml @@ -1,10 +1,10 @@ - + 4.0.0 com.example logdash-example - 0.1.3 + 0.2.0 jar Logdash Example Application @@ -16,21 +16,23 @@ UTF-8 21 - 0.1.3 3.12.1 3.1.1 + + 0.2.0 io.logdash logdash - ${logdash-sdk.version} + ${logdash.version} + org.apache.maven.plugins maven-compiler-plugin @@ -39,6 +41,9 @@ ${maven.compiler.release} -parameters + -Xlint:unchecked + -Xlint:deprecation + -Werror @@ -53,4 +58,25 @@ + + + + snapshot-repo + + + logdash.version + *-SNAPSHOT + + + + + + true + + github-snapshots + https://maven.pkg.github.com/logdash-io/java-sdk + + + + diff --git a/examples/example-springboot/Dockerfile b/examples/example-springboot/Dockerfile new file mode 100644 index 0000000..536bdbc --- /dev/null +++ b/examples/example-springboot/Dockerfile @@ -0,0 +1,7 @@ +FROM eclipse-temurin:21-jre-alpine + +WORKDIR /app +COPY target/springboot-example-*.jar app.jar + +EXPOSE 8080 +ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/examples/example-springboot/docker-compose.yml b/examples/example-springboot/docker-compose.yml new file mode 100644 index 0000000..a86a90e --- /dev/null +++ b/examples/example-springboot/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3.8' +services: + app: + build: . + ports: + - '8080:8080' + environment: + - LOGDASH_API_KEY=${LOGDASH_API_KEY:-your-api-key} + - SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE:-dev} + healthcheck: + test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/actuator/health"] + interval: 30s + timeout: 10s + retries: 3 \ No newline at end of file diff --git a/examples/example-springboot/pom.xml b/examples/example-springboot/pom.xml new file mode 100644 index 0000000..79788d6 --- /dev/null +++ b/examples/example-springboot/pom.xml @@ -0,0 +1,155 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.4.6 + + + + io.logdash.example + springboot-example + 0.2.0 + jar + + Logdash Spring Boot Example + Spring Boot application demonstrating Logdash Java SDK usage + + + 21 + ${java.version} + ${java.version} + ${java.version} + UTF-8 + + + 0.2.0 + + + 3.5.1 + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + + + io.logdash + logdash + ${logdash-sdk.version} + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + + false + + + true + interval:60 + + maven-central-snapshots + Maven Central Snapshots + https://central.sonatype.com/repository/maven-snapshots/ + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + io.logdash.example.SpringBootExampleApplication + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${java.version} + + -parameters + -Xlint:unchecked + -Xlint:deprecation + -Werror + + + + + + org.apache.maven.plugins + maven-help-plugin + ${maven-help-plugin.version} + + + + + + + local-dev + + true + + + + + never + + maven-central-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + + + + + + force-remote + + + + org.apache.maven.plugins + maven-dependency-plugin + + + purge-local-logdash + + purge-local-repository + + initialize + + + io.logdash:logdash + + true + + + + + + + + + + diff --git a/examples/example-springboot/requests.http b/examples/example-springboot/requests.http new file mode 100644 index 0000000..69eed80 --- /dev/null +++ b/examples/example-springboot/requests.http @@ -0,0 +1,23 @@ +### Variables +@baseUrl = http://localhost:8080 + +### Get all pets +GET {{baseUrl}}/api/pets + +### Get pet by ID +GET {{baseUrl}}/api/pets/1 + +### Create a new pet +POST {{baseUrl}}/api/pets +Content-Type: application/json + +{ + "name": "Fluffy", + "type": "DOG" +} + +### Create a random pet +POST {{baseUrl}}/api/pets/random + +### Delete a pet by ID +DELETE {{baseUrl}}/api/pets/3 diff --git a/examples/example-springboot/src/main/java/io/logdash/example/SpringBootExampleApplication.java b/examples/example-springboot/src/main/java/io/logdash/example/SpringBootExampleApplication.java new file mode 100644 index 0000000..7b570be --- /dev/null +++ b/examples/example-springboot/src/main/java/io/logdash/example/SpringBootExampleApplication.java @@ -0,0 +1,14 @@ +package io.logdash.example; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +@SpringBootApplication +@EnableScheduling +public class SpringBootExampleApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBootExampleApplication.class, args); + } +} diff --git a/examples/example-springboot/src/main/java/io/logdash/example/config/LogdashConfiguration.java b/examples/example-springboot/src/main/java/io/logdash/example/config/LogdashConfiguration.java new file mode 100644 index 0000000..f77b6fd --- /dev/null +++ b/examples/example-springboot/src/main/java/io/logdash/example/config/LogdashConfiguration.java @@ -0,0 +1,51 @@ +package io.logdash.example.config; + +import io.logdash.sdk.Logdash; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static io.logdash.example.config.LogdashConfiguration.LogdashProperties; + +@Configuration +@EnableConfigurationProperties(LogdashProperties.class) +public class LogdashConfiguration { + + @Bean + public Logdash logdash(LogdashProperties properties) { + return Logdash.builder() + .apiKey(properties.apiKey()) + .baseUrl(properties.baseUrl()) + .enableConsoleOutput(properties.enableConsoleOutput()) + .enableVerboseLogging(properties.enableVerboseLogging()) + .requestTimeoutMs(properties.requestTimeoutMs()) + .maxConcurrentRequests(properties.maxConcurrentRequests()) + .build(); + } + + @ConfigurationProperties(prefix = "logdash") + public record LogdashProperties( + String apiKey, + String baseUrl, + boolean enableConsoleOutput, + boolean enableVerboseLogging, + long requestTimeoutMs, + int maxConcurrentRequests + ) { + public LogdashProperties { + if (apiKey == null || apiKey.isBlank()) { + throw new IllegalArgumentException("Logdash API key is required"); + } + if (baseUrl == null || baseUrl.isBlank()) { + baseUrl = "https://api.logdash.io"; + } + if (requestTimeoutMs <= 0) { + requestTimeoutMs = 10000L; + } + if (maxConcurrentRequests <= 0) { + maxConcurrentRequests = 20; + } + } + } +} diff --git a/examples/example-springboot/src/main/java/io/logdash/example/controller/PetController.java b/examples/example-springboot/src/main/java/io/logdash/example/controller/PetController.java new file mode 100644 index 0000000..adc240f --- /dev/null +++ b/examples/example-springboot/src/main/java/io/logdash/example/controller/PetController.java @@ -0,0 +1,133 @@ +package io.logdash.example.controller; + +import io.logdash.example.domain.Pet; +import io.logdash.example.domain.PetType; +import io.logdash.example.service.PetService; +import io.logdash.sdk.Logdash; +import io.logdash.sdk.log.LogdashLogger; +import io.logdash.sdk.metrics.LogdashMetrics; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/api/pets") +public class PetController { + + private final PetService petService; + private final LogdashLogger logger; + private final LogdashMetrics metrics; + + public PetController(PetService petService, Logdash logdash) { + this.petService = petService; + this.logger = logdash.logger(); + this.metrics = logdash.metrics(); + } + + @GetMapping + public ResponseEntity> getAllPets() { + var pets = petService.getAllPets(); + + logger.info("Retrieved all pets", Map.of( + "count", pets.size(), + "endpoint", "/api/pets", + "timestamp", LocalDateTime.now() + )); + + metrics.mutate("api.requests.total", 1); + metrics.mutate("api.pets.list.requests", 1); + metrics.set("pets.total.count", pets.size()); + + return ResponseEntity.ok(pets); + } + + @GetMapping("/{id}") + public ResponseEntity getPet(@PathVariable Long id) { + var pet = petService.findById(id); + + if (pet.isPresent()) { + logger.debug("Pet retrieved successfully", Map.of( + "petId", id, + "name", pet.get().name(), + "type", pet.get().type().name() + )); + metrics.mutate("api.pets.get.success", 1); + return ResponseEntity.ok(pet.get()); + } else { + logger.warn("Pet not found", Map.of( + "petId", id + )); + metrics.mutate("api.pets.get.not_found", 1); + return ResponseEntity.notFound().build(); + } + } + + @PostMapping + public ResponseEntity createPet(@RequestBody CreatePetRequest request) { + try { + var pet = petService.addPet(request.name(), request.type()); + + logger.info("Pet created successfully", Map.of( + "petId", pet.id(), + "name", pet.name(), + "type", pet.type().name() + )); + + metrics.mutate("pets.created.total", 1); + metrics.mutate("api.pets.create.success", 1); + metrics.set("pets.total.count", petService.getTotalCount()); + + return ResponseEntity.ok(pet); + + } catch (IllegalArgumentException e) { + logger.error("Pet creation failed", Map.of( + "error", e.getMessage(), + "requestName", request.name(), + "requestType", request.type() + )); + metrics.mutate("api.pets.create.validation_error", 1); + return ResponseEntity.badRequest().build(); + } + } + + @PostMapping("/random") + public ResponseEntity createRandomPet() { + var pet = petService.createRandomPet(); + + logger.info("Random pet created", Map.of( + "petId", pet.id(), + "name", pet.name(), + "type", pet.type().name() + )); + + metrics.mutate("pets.created.random", 1); + metrics.mutate("api.requests.total", 1); + metrics.set("pets.total.count", petService.getTotalCount()); + + return ResponseEntity.ok(pet); + } + + @DeleteMapping("/{id}") + public ResponseEntity deletePet(@PathVariable Long id) { + boolean deleted = petService.deletePet(id); + + if (deleted) { + logger.info("Pet deleted successfully", Map.of( + "petId", id + )); + metrics.mutate("pets.deleted.total", 1); + metrics.set("pets.total.count", petService.getTotalCount()); + return ResponseEntity.noContent().build(); + } else { + logger.warn("Delete failed - pet not found", Map.of("petId", id)); + metrics.mutate("api.pets.delete.not_found", 1); + return ResponseEntity.notFound().build(); + } + } + + public record CreatePetRequest(String name, PetType type) { + } +} diff --git a/examples/example-springboot/src/main/java/io/logdash/example/domain/Pet.java b/examples/example-springboot/src/main/java/io/logdash/example/domain/Pet.java new file mode 100644 index 0000000..004fbd5 --- /dev/null +++ b/examples/example-springboot/src/main/java/io/logdash/example/domain/Pet.java @@ -0,0 +1,16 @@ +package io.logdash.example.domain; + +public record Pet( + Long id, + String name, + PetType type +) { + public Pet { + if (name == null || name.isBlank()) { + throw new IllegalArgumentException("Pet name is required"); + } + if (type == null) { + throw new IllegalArgumentException("Pet type is required"); + } + } +} diff --git a/examples/example-springboot/src/main/java/io/logdash/example/domain/PetType.java b/examples/example-springboot/src/main/java/io/logdash/example/domain/PetType.java new file mode 100644 index 0000000..20cda4b --- /dev/null +++ b/examples/example-springboot/src/main/java/io/logdash/example/domain/PetType.java @@ -0,0 +1,5 @@ +package io.logdash.example.domain; + +public enum PetType { + DOG, CAT, BIRD, RABBIT, FISH +} diff --git a/examples/example-springboot/src/main/java/io/logdash/example/service/MonitoringService.java b/examples/example-springboot/src/main/java/io/logdash/example/service/MonitoringService.java new file mode 100644 index 0000000..c640ae5 --- /dev/null +++ b/examples/example-springboot/src/main/java/io/logdash/example/service/MonitoringService.java @@ -0,0 +1,88 @@ +package io.logdash.example.service; + +import io.logdash.sdk.Logdash; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import java.lang.management.ManagementFactory; +import java.util.Map; +import java.util.concurrent.ThreadLocalRandom; + +@Service +public class MonitoringService { + + private final Logdash logdash; + private final PetService petService; + private int monitoringCycles = 0; + + public MonitoringService(Logdash logdash, PetService petService) { + this.logdash = logdash; + this.petService = petService; + } + + @Scheduled(fixedRate = 10000) // Every 10 seconds + public void recordSystemMetrics() { + var logger = logdash.logger(); + var metrics = logdash.metrics(); + + monitoringCycles++; + + // JVM metrics + var memoryBean = ManagementFactory.getMemoryMXBean(); + var heapUsage = memoryBean.getHeapMemoryUsage(); + + var heapUsedMB = heapUsage.getUsed() / (1024 * 1024); + + // Simulated application metrics + var activeUsers = ThreadLocalRandom.current().nextInt(50, 300); + var errorRate = ThreadLocalRandom.current().nextDouble(0.1, 8.0); + + logger.verbose("System monitoring cycle", Map.of( + "cycle", monitoringCycles, + "activeUsers", activeUsers + )); + + // Send metrics to Logdash + metrics.set("jvm.memory.heap.used_mb", heapUsedMB); + metrics.set("app.users.active", activeUsers); + + // Business metrics + var petCount = petService.getTotalCount(); + metrics.set("pets.total.count", petCount); + + // Increment counters + metrics.mutate("monitoring.cycles.total", 1); + + // Simulate random events + if (ThreadLocalRandom.current().nextDouble() < 0.3) { // 30% chance + logger.info("Random application event", Map.of( + "activeUsers", activeUsers + )); + metrics.mutate("app.events.user_activity", 1); + } + + if (errorRate > 3.0) { + logger.warn("High error rate detected", Map.of( + "errorRate", errorRate + )); + metrics.mutate("alerts.performance.slow_response", 1); + } + } + + @Scheduled(fixedRate = 30000) // Every 30 seconds + public void simulateBusinessEvents() { + var logger = logdash.logger(); + var metrics = logdash.metrics(); + + // Simulate random pet creation + if (ThreadLocalRandom.current().nextBoolean()) { + var pet = petService.createRandomPet(); + + logger.info(String.format("Background pet creation: petId=%s, name=%s, type=%s", pet.id(), pet.name(), + pet.type().name())); + + metrics.mutate("pets.created.background", 1); + metrics.set("pets.total.count", petService.getTotalCount()); + } + } +} diff --git a/examples/example-springboot/src/main/java/io/logdash/example/service/PetService.java b/examples/example-springboot/src/main/java/io/logdash/example/service/PetService.java new file mode 100644 index 0000000..c346210 --- /dev/null +++ b/examples/example-springboot/src/main/java/io/logdash/example/service/PetService.java @@ -0,0 +1,58 @@ +package io.logdash.example.service; + +import io.logdash.example.domain.Pet; +import io.logdash.example.domain.PetType; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicLong; + +@Service +public class PetService { + + private final Map pets = new ConcurrentHashMap<>(); + private final AtomicLong idGenerator = new AtomicLong(1); + + public PetService() { + addPet("Burek", PetType.DOG); + addPet("Mruczek", PetType.CAT); + addPet("Olek", PetType.BIRD); + } + + public Pet addPet(String name, PetType type) { + var pet = new Pet(idGenerator.getAndIncrement(), name, type); + pets.put(pet.id(), pet); + return pet; + } + + public List getAllPets() { + return new ArrayList<>(pets.values()); + } + + public Optional findById(Long id) { + return Optional.ofNullable(pets.get(id)); + } + + public Pet createRandomPet() { + var names = List.of("Azor", "Bella", "Charlie", "Luna", "Max", "Molly", "Oscar"); + var types = PetType.values(); + + var randomName = names.get(ThreadLocalRandom.current().nextInt(names.size())); + var randomType = types[ThreadLocalRandom.current().nextInt(types.length)]; + + return addPet(randomName, randomType); + } + + public int getTotalCount() { + return pets.size(); + } + + public boolean deletePet(Long id) { + return pets.remove(id) != null; + } +} diff --git a/examples/example-springboot/src/main/resources/application.yml b/examples/example-springboot/src/main/resources/application.yml new file mode 100644 index 0000000..e4339c1 --- /dev/null +++ b/examples/example-springboot/src/main/resources/application.yml @@ -0,0 +1,28 @@ +server: + port: 8080 + +spring: + application: + name: logdash-petclinic-demo + +logdash: + api-key: ${LOGDASH_API_KEY:your-api-key} + base-url: https://api.logdash.io + enable-console-output: true + enable-verbose-logging: false + request-timeout-ms: 10000 + max-concurrent-requests: 20 + +management: + endpoints: + web: + exposure: + include: health,info,metrics + endpoint: + health: + show-details: always + +logging: + level: + io.logdash.example: INFO + root: WARN \ No newline at end of file diff --git a/examples/example-springboot/src/test/java/io/logdash/example/SpringBootExampleApplicationTest.java b/examples/example-springboot/src/test/java/io/logdash/example/SpringBootExampleApplicationTest.java new file mode 100644 index 0000000..a996ba5 --- /dev/null +++ b/examples/example-springboot/src/test/java/io/logdash/example/SpringBootExampleApplicationTest.java @@ -0,0 +1,72 @@ +package io.logdash.example; + +import io.logdash.sdk.Logdash; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.TestPropertySource; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@TestPropertySource(properties = { + "logdash.api-key=test-key", + "logdash.enable-console-output=false", + "logdash.enable-verbose-logging=false" +}) +class SpringBootExampleApplicationTest { + + @LocalServerPort + private int port; + + @Autowired + private TestRestTemplate restTemplate; + + @Autowired + private Logdash logdash; + + @Test + void should_start_application_context() { + assertThat(logdash).isNotNull(); + assertThat(logdash.logger()).isNotNull(); + assertThat(logdash.metrics()).isNotNull(); + } + + @Test + void should_get_all_pets() { + var response = restTemplate.getForEntity( + "http://localhost:" + port + "/api/pets", + String.class + ); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).contains("Burek", "Mruczek", "Olek"); + } + + @Test + void should_create_random_pet() { + var response = restTemplate.postForEntity( + "http://localhost:" + port + "/api/pets/random", + null, + String.class + ); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isNotBlank(); + } + + @Test + void should_expose_actuator_health_endpoint() { + var response = restTemplate.getForEntity( + "http://localhost:" + port + "/actuator/health", + String.class + ); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).contains("\"status\":\"UP\""); + } + +} diff --git a/examples/example-springboot/src/test/java/io/logdash/example/controller/PetControllerTest.java b/examples/example-springboot/src/test/java/io/logdash/example/controller/PetControllerTest.java new file mode 100644 index 0000000..09ac17a --- /dev/null +++ b/examples/example-springboot/src/test/java/io/logdash/example/controller/PetControllerTest.java @@ -0,0 +1,167 @@ +package io.logdash.example.controller; + +import io.logdash.example.domain.Pet; +import io.logdash.example.domain.PetType; +import io.logdash.example.service.PetService; +import io.logdash.sdk.log.LogdashLogger; +import io.logdash.sdk.metrics.LogdashMetrics; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.List; +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@WebMvcTest(PetController.class) +@TestPropertySource(properties = { + "logdash.api-key=test-key", + "logdash.enable-console-output=false" +}) +class PetControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockitoBean + private PetService petService; + + @MockitoBean + private LogdashLogger logger; + + @MockitoBean + private LogdashMetrics metrics; + + @Test + void should_get_all_pets() throws Exception { + // Given + var pets = List.of( + new Pet(1L, "Burek", PetType.DOG), + new Pet(2L, "Mruczek", PetType.CAT) + ); + given(petService.getAllPets()).willReturn(pets); + + // When & Then + mockMvc.perform(get("/api/pets")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$").isArray()) + .andExpect(jsonPath("$.length()").value(2)) + .andExpect(jsonPath("$[0].name").value("Burek")) + .andExpect(jsonPath("$[1].name").value("Mruczek")); + + // Verify logging and metrics + verify(logger).info(eq("Retrieved all pets"), anyMap()); + verify(metrics).mutate("api.requests.total", 1); + verify(metrics).mutate("api.pets.list.requests", 1); + verify(metrics).set("pets.total.count", 2); + } + + @Test + void should_get_pet_by_id() throws Exception { + // Given + var pet = new Pet(1L, "Burek", PetType.DOG); + given(petService.findById(1L)).willReturn(Optional.of(pet)); + + // When & Then + mockMvc.perform(get("/api/pets/1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(1)) + .andExpect(jsonPath("$.name").value("Burek")) + .andExpect(jsonPath("$.type").value("DOG")); + + // Verify logging and metrics + verify(logger).debug(eq("Fetching pet with id: {}"), anyMap()); + verify(logger).info(eq("Pet found"), anyMap()); + verify(metrics).mutate("api.pets.found", 1); + } + + @Test + void should_return_not_found_for_non_existent_pet() throws Exception { + // Given + given(petService.findById(999L)).willReturn(Optional.empty()); + + // When & Then + mockMvc.perform(get("/api/pets/999")) + .andExpect(status().isNotFound()); + + // Verify logging and metrics + verify(logger).debug(eq("Fetching pet with id: {}"), anyMap()); + verify(logger).warn(eq("Pet not found"), anyMap()); + verify(metrics).mutate("api.pets.not_found", 1); + } + + @Test + void should_create_random_pet() throws Exception { + // Given + var pet = new Pet(3L, "Lucky", PetType.DOG); + given(petService.createRandomPet()).willReturn(pet); + + // When & Then + mockMvc.perform(post("/api/pets/random")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(3)) + .andExpect(jsonPath("$.name").value("Lucky")) + .andExpect(jsonPath("$.type").value("DOG")); + + // Verify logging and metrics + verify(logger).info(eq("Created random pet"), anyMap()); + verify(metrics).mutate("api.pets.created", 1); + verify(metrics).mutate("api.pets.random.created", 1); + } + + @Test + void should_create_pet_with_valid_request() throws Exception { + // Given + var pet = new Pet(4L, "Bella", PetType.CAT); + given(petService.addPet("Bella", PetType.CAT)).willReturn(pet); + + // When & Then + mockMvc.perform(post("/api/pets") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + { + "name": "Bella", + "type": "CAT" + } + """)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(4)) + .andExpect(jsonPath("$.name").value("Bella")) + .andExpect(jsonPath("$.type").value("CAT")); + + // Verify logging and metrics + verify(logger).info(eq("Created pet"), anyMap()); + verify(metrics).mutate("api.pets.created", 1); + verify(metrics).mutate("api.pets.manual.created", 1); + } + + @Test + void should_handle_delete_pet() throws Exception { + // Given + given(petService.deletePet(1L)).willReturn(true); + + // When & Then + mockMvc.perform(delete("/api/pets/1")) + .andExpect(status().isNoContent()); + } + + @Test + void should_handle_delete_non_existent_pet() throws Exception { + // Given + given(petService.deletePet(999L)).willReturn(false); + + // When & Then + mockMvc.perform(delete("/api/pets/999")) + .andExpect(status().isNotFound()); + } +} diff --git a/examples/example-springboot/src/test/resources/application-test.yml b/examples/example-springboot/src/test/resources/application-test.yml new file mode 100644 index 0000000..4e99e94 --- /dev/null +++ b/examples/example-springboot/src/test/resources/application-test.yml @@ -0,0 +1,17 @@ +spring: + main: + banner-mode: off + output: + ansi: + enabled: never + +logdash: + api-key: test-key + enable-console-output: false + enable-verbose-logging: false + +logging: + level: + io.logdash.example: WARN + org.springframework: WARN + org.mockito: WARN diff --git a/pom.xml b/pom.xml index 505e95e..dbc609e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ io.logdash logdash - 0.1.3 + 0.2.0 jar Logdash Java SDK @@ -35,19 +35,6 @@ https://github.com/logdash-io/java-sdk - - - github - GitHub Packages - https://maven.pkg.github.com/logdash-io/java-sdk - - - github - GitHub Packages - https://maven.pkg.github.com/logdash-io/java-sdk - - - 17 ${java.version} @@ -191,7 +178,7 @@ maven-compiler-plugin ${maven-compiler-plugin.version} - ${java.version} + ${maven.compiler.release} -parameters -Xlint:unchecked @@ -429,6 +416,13 @@ true 4 + + src/main/java/**/*.java + src/test/java/**/*.java + examples/**/src/main/java/**/*.java + examples/**/src/test/java/**/*.java + check-deployed-package/**/*.java + **/target/** **/generated/** @@ -438,6 +432,7 @@ **/*.md + examples/**/*.md @@ -459,6 +454,7 @@ pom.xml **/pom.xml + examples/**/pom.xml false @@ -483,6 +479,29 @@ + + local-dev + + true + + + false + false + + + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + true + + + + + + github-release @@ -492,6 +511,18 @@ 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 + + @@ -501,6 +532,7 @@ ${maven-deploy-plugin.version} true + false @@ -519,7 +551,7 @@ central Central Repository Snapshots - https://central.sonatype.com/api/v1/publisher + https://central.sonatype.com/repository/maven-snapshots/ @@ -563,6 +595,15 @@ + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + false + + diff --git a/scripts/dev-cycle.sh b/scripts/dev-cycle.sh new file mode 100755 index 0000000..4322e7f --- /dev/null +++ b/scripts/dev-cycle.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e + +echo "🔧 Building local Logdash SDK..." +mvn clean install -DskipTests + +echo "🚀 Testing SpringBoot example with local snapshot..." +cd examples/example-springboot +mvn clean spring-boot:run -Plocal-dev + +echo "✅ Development cycle completed!" diff --git a/src/main/java/io/logdash/sdk/transport/HttpTransport.java b/src/main/java/io/logdash/sdk/transport/HttpTransport.java index c649b72..217537b 100644 --- a/src/main/java/io/logdash/sdk/transport/HttpTransport.java +++ b/src/main/java/io/logdash/sdk/transport/HttpTransport.java @@ -38,7 +38,7 @@ public final class HttpTransport implements LogdashTransport, AutoCloseable { private static final String METRICS_ENDPOINT = "/metrics"; private static final String API_KEY_HEADER = "project-api-key"; - private static final String USER_AGENT = "logdash-java-sdk/0.1.3"; + private static final String USER_AGENT = "logdash-java-sdk/0.2.0"; private static final String CONTENT_TYPE = "application/json"; private final LogdashConfig config; diff --git a/src/test/java/io/logdash/sdk/transport/HttpTransportTest.java b/src/test/java/io/logdash/sdk/transport/HttpTransportTest.java index ed5c620..1f73fd0 100644 --- a/src/test/java/io/logdash/sdk/transport/HttpTransportTest.java +++ b/src/test/java/io/logdash/sdk/transport/HttpTransportTest.java @@ -82,7 +82,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.1.3"))); + .withHeader("User-Agent", equalTo("logdash-java-sdk/0.2.0"))); } @Test @@ -105,7 +105,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.1.3"))); + .withHeader("User-Agent", equalTo("logdash-java-sdk/0.2.0"))); } @ParameterizedTest