Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.22.0"
".": "0.23.0"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 40
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/sent/sent-dm-7bb26574b68a4a83fda65dd095f3f54fc797d44988eb3ed8b72f6f1be768d284.yml
openapi_spec_hash: 92349dc439d33c6d4bd2a467a36a6190
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/sent/sent-dm-21f3ad999906b6b886f79e15991d43f65bea811dec0a033e3cbe8730aec83f56.yml
openapi_spec_hash: 5b1e9de79d27d3ccd1ee2847f117be46
config_hash: 7fe4b7f38470a511342b783de698aa99
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 0.23.0 (2026-05-07)

Full Changelog: [v0.22.0...v0.23.0](https://github.com/sentdm/sent-dm-java/compare/v0.22.0...v0.23.0)

### Features

* **client:** improve logging ([fcbd456](https://github.com/sentdm/sent-dm-java/commit/fcbd4563cbfd02d714a9dfe8fdbf991c4f10161b))

## 0.22.0 (2026-05-06)

Full Changelog: [v0.21.0...v0.22.0](https://github.com/sentdm/sent-dm-java/compare/v0.21.0...v0.22.0)
Expand Down
25 changes: 18 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

<!-- x-release-please-start-version -->

[![Maven Central](https://img.shields.io/maven-central/v/dm.sent/sent-java)](https://central.sonatype.com/artifact/dm.sent/sent-java/0.22.0)
[![javadoc](https://javadoc.io/badge2/dm.sent/sent-java/0.22.0/javadoc.svg)](https://javadoc.io/doc/dm.sent/sent-java/0.22.0)
[![Maven Central](https://img.shields.io/maven-central/v/dm.sent/sent-java)](https://central.sonatype.com/artifact/dm.sent/sent-java/0.23.0)
[![javadoc](https://javadoc.io/badge2/dm.sent/sent-java/0.23.0/javadoc.svg)](https://javadoc.io/doc/dm.sent/sent-java/0.23.0)

<!-- x-release-please-end -->

Expand All @@ -22,7 +22,7 @@ Use the Sent MCP Server to enable AI assistants to interact with this API, allow

<!-- x-release-please-start-version -->

The REST API documentation can be found on [docs.sent.dm](https://docs.sent.dm). Javadocs are available on [javadoc.io](https://javadoc.io/doc/dm.sent/sent-java/0.22.0).
The REST API documentation can be found on [docs.sent.dm](https://docs.sent.dm). Javadocs are available on [javadoc.io](https://javadoc.io/doc/dm.sent/sent-java/0.23.0).

<!-- x-release-please-end -->

Expand All @@ -33,7 +33,7 @@ The REST API documentation can be found on [docs.sent.dm](https://docs.sent.dm).
### Gradle

```kotlin
implementation("dm.sent:sent-java:0.22.0")
implementation("dm.sent:sent-java:0.23.0")
```

### Maven
Expand All @@ -42,7 +42,7 @@ implementation("dm.sent:sent-java:0.22.0")
<dependency>
<groupId>dm.sent</groupId>
<artifactId>sent-java</artifactId>
<version>0.22.0</version>
<version>0.23.0</version>
</dependency>
```

Expand Down Expand Up @@ -294,8 +294,6 @@ The SDK throws custom unchecked exception types:

## Logging

The SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor).

Enable logging by setting the `SENT_LOG` environment variable to `info`:

```sh
Expand All @@ -308,6 +306,19 @@ Or to `debug` for more verbose logging:
export SENT_LOG=debug
```

Or configure the client manually using the `logLevel` method:

```java
import dm.sent.client.SentClient;
import dm.sent.client.okhttp.SentOkHttpClient;
import dm.sent.core.LogLevel;

SentClient client = SentOkHttpClient.builder()
.fromEnv()
.logLevel(LogLevel.INFO)
.build();
```

## ProGuard and R8

Although the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `sent-java-core` is published with a [configuration file](sent-java-core/src/main/resources/META-INF/proguard/sent-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage).
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ repositories {

allprojects {
group = "dm.sent"
version = "0.22.0" // x-release-please-version
version = "0.23.0" // x-release-please-version
}

subprojects {
Expand Down
1 change: 0 additions & 1 deletion sent-java-client-okhttp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ dependencies {
api(project(":sent-java-core"))

implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")

testImplementation(kotlin("test"))
testImplementation("org.assertj:assertj-core:3.27.7")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import okio.BufferedSink
import okio.buffer
import okio.sink
Expand Down Expand Up @@ -93,18 +92,6 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
private fun newCall(request: HttpRequest, requestOptions: RequestOptions): Call {
val clientBuilder = okHttpClient.newBuilder()

val logLevel =
when (System.getenv("SENT_LOG")?.lowercase()) {
"info" -> HttpLoggingInterceptor.Level.BASIC
"debug" -> HttpLoggingInterceptor.Level.BODY
else -> null
}
if (logLevel != null) {
clientBuilder.addNetworkInterceptor(
HttpLoggingInterceptor().setLevel(logLevel).apply { redactHeader("x-api-key") }
)
}

requestOptions.timeout?.let {
clientBuilder
.connectTimeout(it.connect())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper
import dm.sent.client.SentClient
import dm.sent.client.SentClientImpl
import dm.sent.core.ClientOptions
import dm.sent.core.LogLevel
import dm.sent.core.Sleeper
import dm.sent.core.Timeout
import dm.sent.core.http.Headers
Expand Down Expand Up @@ -277,6 +278,15 @@ class SentOkHttpClient private constructor() {
*/
fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) }

/**
* The level at which to log request and response information.
*
* [fromEnv] will set the level from environment variables. See [LogLevel.fromEnv].
*
* Defaults to [LogLevel.fromEnv].
*/
fun logLevel(logLevel: LogLevel) = apply { clientOptions.logLevel(logLevel) }

/**
* Customer API key for authentication. Use `sk_live_*` keys for production and `sk_test_*`
* keys for sandbox/testing. Pass via the `x-api-key` header.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper
import dm.sent.client.SentClientAsync
import dm.sent.client.SentClientAsyncImpl
import dm.sent.core.ClientOptions
import dm.sent.core.LogLevel
import dm.sent.core.Sleeper
import dm.sent.core.Timeout
import dm.sent.core.http.Headers
Expand Down Expand Up @@ -277,6 +278,15 @@ class SentOkHttpClientAsync private constructor() {
*/
fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) }

/**
* The level at which to log request and response information.
*
* [fromEnv] will set the level from environment variables. See [LogLevel.fromEnv].
*
* Defaults to [LogLevel.fromEnv].
*/
fun logLevel(logLevel: LogLevel) = apply { clientOptions.logLevel(logLevel) }

/**
* Customer API key for authentication. Use `sk_live_*` keys for production and `sk_test_*`
* keys for sandbox/testing. Pass via the `x-api-key` header.
Expand Down
30 changes: 29 additions & 1 deletion sent-java-core/src/main/kotlin/dm/sent/core/ClientOptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package dm.sent.core
import com.fasterxml.jackson.databind.json.JsonMapper
import dm.sent.core.http.Headers
import dm.sent.core.http.HttpClient
import dm.sent.core.http.LoggingHttpClient
import dm.sent.core.http.PhantomReachableClosingHttpClient
import dm.sent.core.http.QueryParams
import dm.sent.core.http.RetryingHttpClient
Expand Down Expand Up @@ -96,6 +97,14 @@ private constructor(
* Defaults to 2.
*/
@get:JvmName("maxRetries") val maxRetries: Int,
/**
* The level at which to log request and response information.
*
* [fromEnv] will set the level from environment variables. See [LogLevel.fromEnv].
*
* Defaults to [LogLevel.fromEnv].
*/
@get:JvmName("logLevel") val logLevel: LogLevel,
/**
* Customer API key for authentication. Use `sk_live_*` keys for production and `sk_test_*` keys
* for sandbox/testing. Pass via the `x-api-key` header.
Expand Down Expand Up @@ -155,6 +164,7 @@ private constructor(
private var responseValidation: Boolean = false
private var timeout: Timeout = Timeout.default()
private var maxRetries: Int = 2
private var logLevel: LogLevel = LogLevel.fromEnv()
private var apiKey: String? = null

@JvmSynthetic
Expand All @@ -170,6 +180,7 @@ private constructor(
responseValidation = clientOptions.responseValidation
timeout = clientOptions.timeout
maxRetries = clientOptions.maxRetries
logLevel = clientOptions.logLevel
apiKey = clientOptions.apiKey
}

Expand Down Expand Up @@ -280,6 +291,15 @@ private constructor(
*/
fun maxRetries(maxRetries: Int) = apply { this.maxRetries = maxRetries }

/**
* The level at which to log request and response information.
*
* [fromEnv] will set the level from environment variables. See [LogLevel.fromEnv].
*
* Defaults to [LogLevel.fromEnv].
*/
fun logLevel(logLevel: LogLevel) = apply { this.logLevel = logLevel }

/**
* Customer API key for authentication. Use `sk_live_*` keys for production and `sk_test_*`
* keys for sandbox/testing. Pass via the `x-api-key` header.
Expand Down Expand Up @@ -381,6 +401,7 @@ private constructor(
* System properties take precedence over environment variables.
*/
fun fromEnv() = apply {
logLevel(LogLevel.fromEnv())
(System.getProperty("sent.baseUrl") ?: System.getenv("SENT_BASE_URL"))?.let {
baseUrl(it)
}
Expand Down Expand Up @@ -437,7 +458,13 @@ private constructor(
return ClientOptions(
httpClient,
RetryingHttpClient.builder()
.httpClient(httpClient)
.httpClient(
LoggingHttpClient.builder()
.httpClient(httpClient)
.clock(clock)
.level(logLevel)
.build()
)
.sleeper(sleeper)
.clock(clock)
.maxRetries(maxRetries)
Expand All @@ -452,6 +479,7 @@ private constructor(
responseValidation,
timeout,
maxRetries,
logLevel,
apiKey,
)
}
Expand Down
33 changes: 33 additions & 0 deletions sent-java-core/src/main/kotlin/dm/sent/core/LogLevel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// File generated from our OpenAPI spec by Stainless.

package dm.sent.core

/** The level at which to log request and response information. */
enum class LogLevel {
/** No logging. */
OFF,
/** Minimal request and response summary logs. No headers or bodies are logged. */
INFO,
/** [INFO] logs plus details about request failures. */
ERROR,
/**
* Full request and response logs. Sensitive headers are redacted, but sensitive data in request
* and response bodies may still be visible.
*/
DEBUG;

/** Returns whether this level is at or higher than the given [level]. */
fun shouldLog(level: LogLevel): Boolean = ordinal >= level.ordinal

companion object {

/** Returns a [LogLevel] based on the `SENT_LOG` environment variable. */
fun fromEnv() =
when (System.getenv("SENT_LOG")?.lowercase()) {
"info" -> INFO
"error" -> ERROR
"debug" -> DEBUG
else -> OFF
}
}
}
6 changes: 6 additions & 0 deletions sent-java-core/src/main/kotlin/dm/sent/core/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package dm.sent.core
import dm.sent.errors.SentInvalidDataException
import java.util.Collections
import java.util.SortedMap
import java.util.SortedSet
import java.util.concurrent.CompletableFuture
import java.util.concurrent.locks.Lock

Expand All @@ -16,6 +17,11 @@ internal fun <T : Any> T?.getOrThrow(name: String): T =
internal fun <T> List<T>.toImmutable(): List<T> =
if (isEmpty()) Collections.emptyList() else Collections.unmodifiableList(toList())

@JvmSynthetic
internal fun <V : Comparable<V>> SortedSet<V>.toImmutable(): SortedSet<V> =
if (isEmpty()) Collections.emptySortedSet()
else Collections.unmodifiableSortedSet(toSortedSet(comparator() ?: Comparator.naturalOrder()))

@JvmSynthetic
internal fun <K, V> Map<K, V>.toImmutable(): Map<K, V> =
if (isEmpty()) immutableEmptyMap() else Collections.unmodifiableMap(toMap())
Expand Down
Loading
Loading