diff --git a/CHANGELOG.md b/CHANGELOG.md index 0893bc2f..2ff19e5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +### Added + +- now in `upload` and `export-to-md` commands you can enable logging of http requests/responses and configure request + timeout + ### Changed - dependency updates: diff --git a/cli/src/main/kotlin/com/github/zeldigas/text2confl/cli/CliOptions.kt b/cli/src/main/kotlin/com/github/zeldigas/text2confl/cli/CliOptions.kt index bdc09603..dc7ab283 100644 --- a/cli/src/main/kotlin/com/github/zeldigas/text2confl/cli/CliOptions.kt +++ b/cli/src/main/kotlin/com/github/zeldigas/text2confl/cli/CliOptions.kt @@ -2,16 +2,16 @@ package com.github.zeldigas.text2confl.cli import com.github.ajalt.clikt.core.ParameterHolder import com.github.ajalt.clikt.core.PrintMessage -import com.github.ajalt.clikt.parameters.options.convert -import com.github.ajalt.clikt.parameters.options.help -import com.github.ajalt.clikt.parameters.options.option -import com.github.ajalt.clikt.parameters.options.required +import com.github.ajalt.clikt.parameters.options.* import com.github.ajalt.clikt.parameters.types.enum import com.github.ajalt.clikt.parameters.types.file +import com.github.ajalt.clikt.parameters.types.long import com.github.zeldigas.confclient.ConfluenceAuth +import com.github.zeldigas.confclient.ConfluenceClientConfig import com.github.zeldigas.confclient.PasswordAuth import com.github.zeldigas.confclient.TokenAuth import com.github.zeldigas.text2confl.convert.EditorVersion +import io.ktor.client.plugins.logging.* import io.ktor.http.* fun ParameterHolder.confluenceUrl() = option( @@ -51,12 +51,24 @@ fun ParameterHolder.docsLocation() = option("--docs") .file(canBeFile = true, canBeDir = true).required() .help("File or directory with files to convert") +fun ParameterHolder.httpLoggingLevel() = option( + "--http-request-logging", + help = "Logging level for http requests. Useful for debugging purposes. Turned off by default" +).enum().default(LogLevel.NONE) + +fun ParameterHolder.httpRequestTimeout() = option( + "--http-request-timeout", + help = "Http request timeout in milliseconds. Default " +).long() + internal interface WithConfluenceServerOptions { val confluenceUrl: Url? val confluenceUser: String? val confluencePassword: String? val accessToken: String? val skipSsl: Boolean? + val httpLogLevel: LogLevel + val httpRequestTimeout: Long? val confluenceAuth: ConfluenceAuth get() = when { @@ -76,6 +88,13 @@ internal interface WithConfluenceServerOptions { return PasswordAuth(username, effectivePassword) } + fun httpClientConfig(server: Url, defaultSslSkip: Boolean = false) = ConfluenceClientConfig( + server = server, + skipSsl = skipSsl ?: defaultSslSkip, + auth = confluenceAuth, + httpLogLevel = httpLogLevel, + requestTimeout = httpRequestTimeout + ) fun askForSecret(prompt: String, requireConfirmation: Boolean = true): String? } diff --git a/cli/src/main/kotlin/com/github/zeldigas/text2confl/cli/DumpToMarkdown.kt b/cli/src/main/kotlin/com/github/zeldigas/text2confl/cli/DumpToMarkdown.kt index 7a6c5a84..591c4780 100644 --- a/cli/src/main/kotlin/com/github/zeldigas/text2confl/cli/DumpToMarkdown.kt +++ b/cli/src/main/kotlin/com/github/zeldigas/text2confl/cli/DumpToMarkdown.kt @@ -7,8 +7,8 @@ import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.options.required import com.github.ajalt.clikt.parameters.types.file -import com.github.zeldigas.confclient.ConfluenceClientConfig import com.github.zeldigas.text2confl.core.ServiceProvider +import io.ktor.client.plugins.logging.* import io.ktor.http.* import kotlinx.coroutines.runBlocking import java.io.File @@ -20,6 +20,9 @@ class DumpToMarkdown : CliktCommand(name = "export-to-md", help = "Exports confl override val confluencePassword: String? by confluencePassword() override val accessToken: String? by accessToken() override val skipSsl: Boolean? by skipSsl() + override val httpLogLevel: LogLevel by httpLoggingLevel() + override val httpRequestTimeout: Long? by httpRequestTimeout() + val space: String? by confluenceSpace() private val pageId: String? by option("--page-id", help = "Id of page that you want to dump") private val pageTitle: String? by option( @@ -47,11 +50,7 @@ class DumpToMarkdown : CliktCommand(name = "export-to-md", help = "Exports confl } private suspend fun dumpPage() { - val clientConfig = ConfluenceClientConfig( - confluenceUrl, - skipSsl ?: true, - confluenceAuth - ) + val clientConfig = httpClientConfig(confluenceUrl) val client = serviceProvider.createConfluenceClient(clientConfig, false) val pageExporter = serviceProvider.createPageExporter(client, saveContentSource) diff --git a/cli/src/main/kotlin/com/github/zeldigas/text2confl/cli/Upload.kt b/cli/src/main/kotlin/com/github/zeldigas/text2confl/cli/Upload.kt index 1e9992e6..90a26600 100644 --- a/cli/src/main/kotlin/com/github/zeldigas/text2confl/cli/Upload.kt +++ b/cli/src/main/kotlin/com/github/zeldigas/text2confl/cli/Upload.kt @@ -13,6 +13,7 @@ import com.github.zeldigas.text2confl.convert.EditorVersion import com.github.zeldigas.text2confl.core.ServiceProvider import com.github.zeldigas.text2confl.core.config.* import com.github.zeldigas.text2confl.core.upload.ChangeDetector +import io.ktor.client.plugins.logging.* import io.ktor.http.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking @@ -27,6 +28,8 @@ class Upload : CliktCommand(name = "upload", help = "Converts source files and u override val confluencePassword: String? by confluencePassword() override val accessToken: String? by accessToken() override val skipSsl: Boolean? by skipSsl() + override val httpLogLevel: LogLevel by httpLoggingLevel() + override val httpRequestTimeout: Long? by httpRequestTimeout() override val spaceKey: String? by confluenceSpace() private val parentId: String? by option("--parent-id", help = "Id of parent page where root pages should be added") @@ -110,11 +113,7 @@ class Upload : CliktCommand(name = "upload", help = "Converts source files and u val server = confluenceUrl ?: configuration.server?.let { Url(it) } ?: parameterMissing("Confluence url", "--confluence-url", "server") - return ConfluenceClientConfig( - server = server, - skipSsl = skipSsl ?: configuration.skipSsl, - auth = confluenceAuth - ) + return httpClientConfig(server, configuration.skipSsl) } private fun passwordAuth(username: String, password: String?): PasswordAuth { diff --git a/confluence-client/pom.xml b/confluence-client/pom.xml index 1e4abec5..1194befb 100644 --- a/confluence-client/pom.xml +++ b/confluence-client/pom.xml @@ -47,6 +47,10 @@ io.ktor ktor-client-auth-jvm + + io.ktor + ktor-client-logging-jvm + io.github.oshai diff --git a/confluence-client/src/main/kotlin/com/github/zeldigas/confclient/ConfluenceClientConfig.kt b/confluence-client/src/main/kotlin/com/github/zeldigas/confclient/ConfluenceClientConfig.kt index 988a13e6..66c50d02 100644 --- a/confluence-client/src/main/kotlin/com/github/zeldigas/confclient/ConfluenceClientConfig.kt +++ b/confluence-client/src/main/kotlin/com/github/zeldigas/confclient/ConfluenceClientConfig.kt @@ -1,5 +1,6 @@ package com.github.zeldigas.confclient +import io.ktor.client.plugins.logging.* import io.ktor.http.* /** @@ -8,5 +9,7 @@ import io.ktor.http.* data class ConfluenceClientConfig( val server: Url, val skipSsl: Boolean, - val auth: ConfluenceAuth + val auth: ConfluenceAuth, + val httpLogLevel: LogLevel = LogLevel.NONE, + val requestTimeout: Long? = null, ) \ No newline at end of file diff --git a/confluence-client/src/main/kotlin/com/github/zeldigas/confclient/ConfluenceClientImpl.kt b/confluence-client/src/main/kotlin/com/github/zeldigas/confclient/ConfluenceClientImpl.kt index 777fe5bf..b88f1857 100644 --- a/confluence-client/src/main/kotlin/com/github/zeldigas/confclient/ConfluenceClientImpl.kt +++ b/confluence-client/src/main/kotlin/com/github/zeldigas/confclient/ConfluenceClientImpl.kt @@ -14,6 +14,7 @@ import io.ktor.client.engine.cio.* import io.ktor.client.plugins.* import io.ktor.client.plugins.auth.* import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.plugins.logging.* import io.ktor.client.request.* import io.ktor.client.request.forms.* import io.ktor.client.statement.* @@ -327,8 +328,11 @@ fun confluenceClient( config: ConfluenceClientConfig ): ConfluenceClient { val client = HttpClient(CIO) { - if (config.skipSsl) { - engine { + engine { + if (config.requestTimeout != null) { + requestTimeout = config.requestTimeout + } + if (config.skipSsl) { https { trustManager = object : X509TrustManager { override fun getAcceptedIssuers(): Array? = null @@ -353,6 +357,14 @@ fun confluenceClient( install(UserAgent) { agent = "text2confl" } + if (config.httpLogLevel != LogLevel.NONE) { + install(Logging) { + logger = Logger.DEFAULT + level = config.httpLogLevel + sanitizeHeader { header -> header == HttpHeaders.Authorization } + } + } + } return ConfluenceClientImpl(config.server, "${config.server}/rest/api", client) diff --git a/core/pom.xml b/core/pom.xml index 5b80aebb..401acf19 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -26,6 +26,8 @@ com.fasterxml.jackson.dataformat jackson-dataformat-yaml + + ch.qos.logback logback-classic