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.1.0-alpha.5"
".": "0.1.0-alpha.6"
}
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## 0.1.0-alpha.6 (2026-05-08)

Full Changelog: [v0.1.0-alpha.5...v0.1.0-alpha.6](https://github.com/HubSpot/hubspot-sdk-java/compare/v0.1.0-alpha.5...v0.1.0-alpha.6)

### Features

* **client:** improve logging ([173cea3](https://github.com/HubSpot/hubspot-sdk-java/commit/173cea363bc7dc0d904ece4f9497dc473f165467))


### Chores

* redact api-key headers in debug logs ([eb4db5c](https://github.com/HubSpot/hubspot-sdk-java/commit/eb4db5cde17cde3a9084b100df3c03290ac1eda4))

## 0.1.0-alpha.5 (2026-05-07)

Full Changelog: [v0.1.0-alpha.4...v0.1.0-alpha.5](https://github.com/HubSpot/hubspot-sdk-java/compare/v0.1.0-alpha.4...v0.1.0-alpha.5)
Expand Down
26 changes: 19 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/com.hubspot.sdk/hubspot-java)](https://central.sonatype.com/artifact/com.hubspot.sdk/hubspot-java/0.1.0-alpha.5)
[![javadoc](https://javadoc.io/badge2/com.hubspot.sdk/hubspot-java/0.1.0-alpha.5/javadoc.svg)](https://javadoc.io/doc/com.hubspot.sdk/hubspot-java/0.1.0-alpha.5)
[![Maven Central](https://img.shields.io/maven-central/v/com.hubspot.sdk/hubspot-java)](https://central.sonatype.com/artifact/com.hubspot.sdk/hubspot-java/0.1.0-alpha.6)
[![javadoc](https://javadoc.io/badge2/com.hubspot.sdk/hubspot-java/0.1.0-alpha.6/javadoc.svg)](https://javadoc.io/doc/com.hubspot.sdk/hubspot-java/0.1.0-alpha.6)

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

Expand All @@ -13,7 +13,7 @@ It is generated with [Stainless](https://www.stainless.com/).

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

The REST API documentation can be found on [developers.hubspot.com](https://developers.hubspot.com/docs/api-reference/overview). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.hubspot.sdk/hubspot-java/0.1.0-alpha.5).
The REST API documentation can be found on [developers.hubspot.com](https://developers.hubspot.com/docs/api-reference/overview). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.hubspot.sdk/hubspot-java/0.1.0-alpha.6).

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

Expand All @@ -24,7 +24,7 @@ The REST API documentation can be found on [developers.hubspot.com](https://deve
### Gradle

```kotlin
implementation("com.hubspot.sdk:hubspot-java:0.1.0-alpha.5")
implementation("com.hubspot.sdk:hubspot-java:0.1.0-alpha.6")
```

### Maven
Expand All @@ -33,7 +33,7 @@ implementation("com.hubspot.sdk:hubspot-java:0.1.0-alpha.5")
<dependency>
<groupId>com.hubspot.sdk</groupId>
<artifactId>hubspot-java</artifactId>
<version>0.1.0-alpha.5</version>
<version>0.1.0-alpha.6</version>
</dependency>
```

Expand Down Expand Up @@ -468,8 +468,6 @@ while (true) {

## Logging

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

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

```sh
Expand All @@ -482,6 +480,20 @@ Or to `debug` for more verbose logging:
export HUBSPOT_LOG=debug
```

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

```java
import com.hubspot.sdk.client.HubSpotClient;
import com.hubspot.sdk.client.okhttp.HubSpotOkHttpClient;
import com.hubspot.sdk.core.LogLevel;

HubSpotClient client = HubSpotOkHttpClient.builder()
.fromEnv()
.logLevel(LogLevel.INFO)
.accessToken("My Access Token")
.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 `hubspot-java-core` is published with a [configuration file](hubspot-java-core/src/main/resources/META-INF/proguard/hubspot-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 @@ -9,7 +9,7 @@ repositories {

allprojects {
group = "com.hubspot.sdk"
version = "0.1.0-alpha.5" // x-release-please-version
version = "0.1.0-alpha.6" // x-release-please-version
}

subprojects {
Expand Down
1 change: 0 additions & 1 deletion hubspot-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(":hubspot-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 @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper
import com.hubspot.sdk.client.HubSpotClient
import com.hubspot.sdk.client.HubSpotClientImpl
import com.hubspot.sdk.core.ClientOptions
import com.hubspot.sdk.core.LogLevel
import com.hubspot.sdk.core.Sleeper
import com.hubspot.sdk.core.Timeout
import com.hubspot.sdk.core.http.AsyncStreamResponse
Expand Down Expand Up @@ -290,6 +291,15 @@ class HubSpotOkHttpClient 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) }

fun accessToken(accessToken: String?) = apply { clientOptions.accessToken(accessToken) }

/** Alias for calling [Builder.accessToken] with `accessToken.orElse(null)`. */
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 com.hubspot.sdk.client.HubSpotClientAsync
import com.hubspot.sdk.client.HubSpotClientAsyncImpl
import com.hubspot.sdk.core.ClientOptions
import com.hubspot.sdk.core.LogLevel
import com.hubspot.sdk.core.Sleeper
import com.hubspot.sdk.core.Timeout
import com.hubspot.sdk.core.http.AsyncStreamResponse
Expand Down Expand Up @@ -290,6 +291,15 @@ class HubSpotOkHttpClientAsync 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) }

fun accessToken(accessToken: String?) = apply { clientOptions.accessToken(accessToken) }

/** Alias for calling [Builder.accessToken] with `accessToken.orElse(null)`. */
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("HUBSPOT_LOG")?.lowercase()) {
"info" -> HttpLoggingInterceptor.Level.BASIC
"debug" -> HttpLoggingInterceptor.Level.BODY
else -> null
}
if (logLevel != null) {
clientBuilder.addNetworkInterceptor(
HttpLoggingInterceptor().setLevel(logLevel).apply { redactHeader("Authorization") }
)
}

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 com.hubspot.sdk.core.http.AsyncStreamResponse
import com.hubspot.sdk.core.http.Headers
import com.hubspot.sdk.core.http.HttpClient
import com.hubspot.sdk.core.http.LoggingHttpClient
import com.hubspot.sdk.core.http.PhantomReachableClosingHttpClient
import com.hubspot.sdk.core.http.QueryParams
import com.hubspot.sdk.core.http.RetryingHttpClient
Expand Down Expand Up @@ -110,6 +111,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,
private val accessToken: String?,
private val developerApiKey: String?,
) {
Expand Down Expand Up @@ -170,6 +179,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 accessToken: String? = null
private var developerApiKey: String? = null

Expand All @@ -187,6 +197,7 @@ private constructor(
responseValidation = clientOptions.responseValidation
timeout = clientOptions.timeout
maxRetries = clientOptions.maxRetries
logLevel = clientOptions.logLevel
accessToken = clientOptions.accessToken
developerApiKey = clientOptions.developerApiKey
}
Expand Down Expand Up @@ -312,6 +323,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 }

fun accessToken(accessToken: String?) = apply { this.accessToken = accessToken }

/** Alias for calling [Builder.accessToken] with `accessToken.orElse(null)`. */
Expand Down Expand Up @@ -419,6 +439,7 @@ private constructor(
* System properties take precedence over environment variables.
*/
fun fromEnv() = apply {
logLevel(LogLevel.fromEnv())
(System.getProperty("hubspot.baseUrl") ?: System.getenv("HUBSPOT_BASE_URL"))?.let {
baseUrl(it)
}
Expand Down Expand Up @@ -493,7 +514,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 @@ -509,6 +536,7 @@ private constructor(
responseValidation,
timeout,
maxRetries,
logLevel,
accessToken,
developerApiKey,
)
Expand Down
33 changes: 33 additions & 0 deletions hubspot-java-core/src/main/kotlin/com/hubspot/sdk/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 com.hubspot.sdk.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 `HUBSPOT_LOG` environment variable. */
fun fromEnv() =
when (System.getenv("HUBSPOT_LOG")?.lowercase()) {
"info" -> INFO
"error" -> ERROR
"debug" -> DEBUG
else -> OFF
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package com.hubspot.sdk.core
import com.hubspot.sdk.errors.HubSpotInvalidDataException
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