Kotlin logging

This commit is contained in:
xis 2023-10-10 15:13:59 +02:00
parent 4da6b541d8
commit 4e8ddbb5bf
15 changed files with 180 additions and 176 deletions

View file

@ -23,6 +23,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.fasterxml.jackson.module:jackson-module-kotlin'
implementation 'org.jetbrains.kotlin:kotlin-reflect'
implementation 'io.github.microutils:kotlin-logging:3.0.5'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.mariadb.jdbc:mariadb-java-client:3.2.0'

View file

@ -2,10 +2,10 @@ package net.schowek.nextclouddlna.controller
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import mu.KLogging
import net.schowek.nextclouddlna.nextcloud.content.ContentGroup.*
import net.schowek.nextclouddlna.nextcloud.content.ContentTreeProvider
import net.schowek.nextclouddlna.nextcloud.content.MediaFormat
import net.schowek.nextclouddlna.util.Logging
import org.jupnp.support.model.Protocol
import org.jupnp.support.model.ProtocolInfo
import org.jupnp.support.model.dlna.*
@ -25,7 +25,7 @@ import java.util.*
@RestController
class ContentController(
private val contentTreeProvider: ContentTreeProvider
) : Logging {
) {
@RequestMapping(method = [RequestMethod.GET, RequestMethod.HEAD], value = ["/c/{id}"])
@ResponseBody
fun getResource(
@ -73,5 +73,6 @@ class ContentController(
}
return DLNAProtocolInfo(Protocol.HTTP_GET, ProtocolInfo.WILDCARD, mediaFormat.mime, attributes)
}
companion object: KLogging()
}

View file

@ -41,7 +41,7 @@ class DlnaService(
}
}
private inner class MyUpnpServiceConfiguration : DefaultUpnpServiceConfiguration() {
private inner class MyUpnpServiceConfiguration : DefaultUpnpServiceConfiguration(8081) {
override fun createStreamClient(): StreamClient<*> {
return ApacheStreamClient(
ApacheStreamClientConfiguration(syncProtocolExecutorService)

View file

@ -1,7 +1,7 @@
package net.schowek.nextclouddlna.dlna.media
import mu.KLogging
import net.schowek.nextclouddlna.nextcloud.content.ContentTreeProvider
import net.schowek.nextclouddlna.util.Logging
import org.jupnp.support.contentdirectory.AbstractContentDirectoryService
import org.jupnp.support.contentdirectory.ContentDirectoryErrorCode
import org.jupnp.support.contentdirectory.ContentDirectoryException
@ -25,7 +25,7 @@ class ContentDirectoryService(
) : AbstractContentDirectoryService(
mutableListOf("dc:title", "upnp:class"), // also "dc:creator", "dc:date", "res@size"
mutableListOf("dc:title")
), Logging {
) {
/**
* Root is requested with objectID="0".
@ -77,7 +77,7 @@ class ContentDirectoryService(
}
}
companion object {
companion object : KLogging() {
@Throws(Exception::class)
private fun toRangedResult(
containers: List<Container>,

View file

@ -1,8 +1,8 @@
package net.schowek.nextclouddlna.dlna.media
import jakarta.annotation.PostConstruct
import mu.KLogging
import net.schowek.nextclouddlna.util.ExternalUrls
import net.schowek.nextclouddlna.util.Logging
import org.jupnp.model.meta.*
import org.jupnp.model.types.UDADeviceType
import org.jupnp.model.types.UDN.uniqueSystemIdentifier
@ -21,7 +21,7 @@ class MediaServer(
@Value("\${server.friendlyName}")
private val friendlyName: String,
private val externalUrls: ExternalUrls
) : Logging {
) {
val device = LocalDevice(
DeviceIdentity(uniqueSystemIdentifier("DLNAtoad-MediaServer"), 300),
UDADeviceType(DEVICE_TYPE, VERSION),
@ -34,7 +34,7 @@ class MediaServer(
logger.info("uniqueSystemIdentifier: {} ({})", device.identity.udn, friendlyName)
}
companion object {
companion object : KLogging() {
private const val DEVICE_TYPE = "MediaServer"
private const val VERSION = 1
const val ICON_FILENAME = "icon.png"

View file

@ -1,6 +1,6 @@
package net.schowek.nextclouddlna.dlna.transport
import net.schowek.nextclouddlna.util.Logging
import mu.KLogging
import org.apache.http.*
import org.apache.http.client.ResponseHandler
import org.apache.http.client.config.RequestConfig
@ -30,7 +30,7 @@ import java.util.concurrent.Callable
class ApacheStreamClient(
private val configuration: ApacheStreamClientConfiguration
) : Logging, AbstractStreamClient<ApacheStreamClientConfiguration?, HttpRequestBase>() {
) : AbstractStreamClient<ApacheStreamClientConfiguration?, HttpRequestBase>() {
private val clientConnectionManager: PoolingHttpClientConnectionManager
private val httpClient: CloseableHttpClient
@ -230,7 +230,7 @@ class ApacheStreamClient(
}
}
companion object {
companion object : KLogging() {
private fun addHeaders(httpMessage: HttpMessage, headers: Headers) {
for ((key, value1) in headers) {
for (value in value1) {

View file

@ -1,7 +1,7 @@
package net.schowek.nextclouddlna.dlna.transport
import com.sun.net.httpserver.HttpExchange
import net.schowek.nextclouddlna.util.Logging
import mu.KLogging
import org.jupnp.model.message.*
import org.jupnp.protocol.ProtocolFactory
import org.jupnp.transport.spi.UpnpStream
@ -13,38 +13,34 @@ import java.net.HttpURLConnection
abstract class MyHttpExchangeUpnpStream(
protocolFactory: ProtocolFactory?,
val httpExchange: HttpExchange
) : Logging, UpnpStream(protocolFactory) {
protocolFactory: ProtocolFactory,
private val httpExchange: HttpExchange
) : UpnpStream(protocolFactory) {
override fun run() {
try {
val xchng = httpExchange
// Status
val requestMessage = StreamRequestMessage(
UpnpRequest.Method.getByHttpName(xchng.requestMethod),
xchng.requestURI
UpnpRequest.Method.getByHttpName(httpExchange.requestMethod),
httpExchange.requestURI
)
if (requestMessage.operation.method == UpnpRequest.Method.UNKNOWN) {
logger.warn("Method not supported by UPnP stack: {}", xchng.requestMethod)
throw RuntimeException("Method not supported: {}" + xchng.requestMethod)
logger.warn("Method not supported by UPnP stack: {}", httpExchange.requestMethod)
throw RuntimeException("Method not supported: {}" + httpExchange.requestMethod)
}
// Protocol
requestMessage.operation.httpMinorVersion = if (xchng.protocol.uppercase() == "HTTP/1.1") 1 else 0
requestMessage.operation.httpMinorVersion = if (httpExchange.protocol.uppercase() == "HTTP/1.1") 1 else 0
// Connection wrapper
requestMessage.connection = createConnection()
// Headers
requestMessage.headers = UpnpHeaders(xchng.requestHeaders)
requestMessage.headers = UpnpHeaders(httpExchange.requestHeaders)
// Body
val bodyBytes: ByteArray
var inputStream: InputStream? = null
try {
inputStream = xchng.requestBody
inputStream = httpExchange.requestBody
bodyBytes = IO.readBytes(inputStream)
} finally {
inputStream?.close()
@ -67,13 +63,13 @@ abstract class MyHttpExchangeUpnpStream(
// Return the response
if (responseMessage != null) {
// Headers
xchng.responseHeaders.putAll(responseMessage.headers)
httpExchange.responseHeaders.putAll(responseMessage.headers)
// Body
val responseBodyBytes = if (responseMessage.hasBody()) responseMessage.bodyBytes else null
val contentLength = responseBodyBytes?.size ?: -1
logger.info("Sending HTTP response message: $responseMessage with content length: $contentLength")
xchng.sendResponseHeaders(responseMessage.operation.statusCode, contentLength.toLong())
httpExchange.sendResponseHeaders(responseMessage.operation.statusCode, contentLength.toLong())
if (responseBodyBytes!!.isNotEmpty()) {
logger.debug(" Response body: " + responseMessage.body)
}
@ -81,7 +77,7 @@ abstract class MyHttpExchangeUpnpStream(
logger.debug("Response message has body, writing bytes to stream...")
var outputStream: OutputStream? = null
try {
outputStream = xchng.responseBody
outputStream = httpExchange.responseBody
IO.writeBytes(outputStream, responseBodyBytes)
outputStream.flush()
} finally {
@ -91,11 +87,10 @@ abstract class MyHttpExchangeUpnpStream(
} else {
// If it's null, it's 404, everything else needs a proper httpResponse
logger.info("Sending HTTP response status: " + HttpURLConnection.HTTP_NOT_FOUND)
xchng.sendResponseHeaders(HttpURLConnection.HTTP_NOT_FOUND, -1)
httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_NOT_FOUND, -1)
}
responseSent(responseMessage)
} catch (t: Throwable) {
// You definitely want to catch all Exceptions here, otherwise the server will
// simply close the socket and you get an "unexpected end of file" on the client.
// The same is true if you just rethrow an IOException - it is a mystery why it
@ -116,5 +111,7 @@ abstract class MyHttpExchangeUpnpStream(
}
protected abstract fun createConnection(): Connection?
companion object: KLogging()
}

View file

@ -5,7 +5,7 @@ import org.jupnp.transport.spi.StreamServerConfiguration
class MyStreamServerConfiguration(
private val listenPort: Int
) : StreamServerConfiguration {
var tcpConnectionBacklog = 0
val tcpConnectionBacklog = 0
override fun getListenPort(): Int {
return listenPort
}

View file

@ -3,7 +3,7 @@ package net.schowek.nextclouddlna.dlna.transport
import com.sun.net.httpserver.HttpExchange
import com.sun.net.httpserver.HttpHandler
import com.sun.net.httpserver.HttpServer
import net.schowek.nextclouddlna.util.Logging
import mu.KLogging
import org.jupnp.model.message.Connection
import org.jupnp.transport.Router
import org.jupnp.transport.spi.InitializationException
@ -15,14 +15,14 @@ import java.net.InetSocketAddress
class MyStreamServerImpl(
private val configuration: MyStreamServerConfiguration
) : Logging, StreamServer<MyStreamServerConfiguration> {
protected var server: HttpServer? = null
) : StreamServer<MyStreamServerConfiguration> {
private var server: HttpServer? = null
@Synchronized
@Throws(InitializationException::class)
override fun init(bindAddress: InetAddress, router: Router) {
try {
val socketAddress = InetSocketAddress(bindAddress, configuration.getListenPort())
val socketAddress = InetSocketAddress(bindAddress, configuration.listenPort)
server = HttpServer.create(socketAddress, configuration.tcpConnectionBacklog)
server!!.createContext("/", MyRequestHttpHandler(router))
logger.info("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *")
@ -78,12 +78,14 @@ class MyStreamServerImpl(
* Logs a warning and returns `true`, we can't access the socket using the awful JDK webserver API.
* Override this method if you know how to do it.
*/
protected fun isConnectionOpen(exchange: HttpExchange?): Boolean {
private fun isConnectionOpen(exchange: HttpExchange?): Boolean {
logger.warn("Can't check client connection, socket access impossible on JDK webserver!")
return true
}
protected inner class MyHttpServerConnection(protected var exchange: HttpExchange) : Connection {
private inner class MyHttpServerConnection(
private val exchange: HttpExchange
) : Connection {
override fun isOpen(): Boolean {
return isConnectionOpen(exchange)
}
@ -96,5 +98,7 @@ class MyStreamServerImpl(
return if (exchange.localAddress != null) exchange.localAddress.address else null
}
}
companion object: KLogging()
}

View file

@ -1,13 +1,14 @@
package net.schowek.nextclouddlna.dlna.transport
import io.micrometer.common.util.StringUtils
import net.schowek.nextclouddlna.util.Logging
import mu.KLogging
import org.jupnp.model.message.StreamRequestMessage
import org.jupnp.model.message.StreamResponseMessage
import org.jupnp.model.message.UpnpMessage
object StreamsLoggerHelper : Logging {
class StreamsLoggerHelper {
companion object : KLogging() {
private const val HTTPSERVER_REQUEST_BEGIN =
"================================== HTTPSERVER REQUEST BEGIN ====================================="
private const val HTTPSERVER_REQUEST_END =
@ -40,7 +41,10 @@ object StreamsLoggerHelper : Logging {
)
}
fun logStreamServerResponseMessage(responseMessage: StreamResponseMessage, requestMessage: StreamRequestMessage) {
fun logStreamServerResponseMessage(
responseMessage: StreamResponseMessage,
requestMessage: StreamRequestMessage
) {
val formattedResponse = getFormattedResponse(responseMessage)
val formattedHeaders = getFormattedHeaders(responseMessage)
val formattedBody = getFormattedBody(responseMessage)
@ -70,7 +74,10 @@ object StreamsLoggerHelper : Logging {
)
}
fun logStreamClientResponseMessage(responseMessage: StreamResponseMessage, requestMessage: StreamRequestMessage?) {
fun logStreamClientResponseMessage(
responseMessage: StreamResponseMessage,
requestMessage: StreamRequestMessage?
) {
val formattedResponse = getFormattedResponse(responseMessage)
val formattedHeaders = getFormattedHeaders(responseMessage)
val formattedBody = getFormattedBody(responseMessage)
@ -135,4 +142,5 @@ object StreamsLoggerHelper : Logging {
return formattedBody
}
}
}

View file

@ -1,12 +1,12 @@
package net.schowek.nextclouddlna.nextcloud
import jakarta.annotation.PostConstruct
import mu.KLogging
import net.schowek.nextclouddlna.nextcloud.content.ContentItem
import net.schowek.nextclouddlna.nextcloud.content.ContentNode
import net.schowek.nextclouddlna.nextcloud.content.MediaFormat
import net.schowek.nextclouddlna.nextcloud.db.*
import net.schowek.nextclouddlna.nextcloud.db.Filecache.Companion.FOLDER_MIME_TYPE
import net.schowek.nextclouddlna.util.Logging
import org.springframework.dao.InvalidDataAccessResourceUsageException
import org.springframework.stereotype.Component
import org.springframework.transaction.annotation.Transactional
@ -19,7 +19,7 @@ class MediaDB(
private val mimetypeRepository: MimetypeRepository,
private val filecacheRepository: FilecacheRepository,
private val groupFolderRepository: GroupFolderRepository
) : Logging {
) {
private val thumbStorageId: Int = filecacheRepository.findFirstByPath(nextcloudConfig.appDataDir).storage
private val mimetypes: Map<Int, String> = mimetypeRepository.findAll().associate { it.id to it.mimetype }
private val folderMimeType: Int = mimetypes.entries.find { it.value == FOLDER_MIME_TYPE }!!.key
@ -100,5 +100,7 @@ class MediaDB(
nextcloudConfig.appDataDir + "/" + f.path
}
}
companion object: KLogging()
}

View file

@ -1,8 +1,8 @@
package net.schowek.nextclouddlna.nextcloud
import jakarta.annotation.PostConstruct
import mu.KLogging
import net.schowek.nextclouddlna.nextcloud.db.AppConfigRepository
import net.schowek.nextclouddlna.util.Logging
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
import java.io.File
@ -16,7 +16,7 @@ class NextcloudConfigDiscovery(
@Value("\${nextcloud.filesDir}")
val nextcloudDir: String,
val appConfigRepository: AppConfigRepository
) : Logging {
) {
final val appDataDir: String = findAppDataDir()
final val supportsGroupFolders: Boolean = checkGroupFoldersSupport()
@ -35,7 +35,7 @@ class NextcloudConfigDiscovery(
})).findFirst().orElseThrow().name
}
companion object {
companion object : KLogging() {
const val APPDATA_NAME_PATTERN = "appdata_\\w+"
}
}

View file

@ -1,8 +1,8 @@
package net.schowek.nextclouddlna.nextcloud.content
import jakarta.annotation.PostConstruct
import mu.KLogging
import net.schowek.nextclouddlna.nextcloud.MediaDB
import net.schowek.nextclouddlna.util.Logging
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component
import java.util.concurrent.atomic.AtomicInteger
@ -12,7 +12,7 @@ import java.util.regex.Pattern
@Component
class ContentTreeProvider(
private val mediaDB: MediaDB
) : Logging {
) {
private var tree = buildContentTree()
private var lastMTime = 0L
@ -91,6 +91,8 @@ class ContentTreeProvider(
fun getItem(id: String): ContentItem? = tree.getItem(id)
fun getNode(id: String): ContentNode? = tree.getNode(id)
companion object : KLogging()
}

View file

@ -1,14 +0,0 @@
package net.schowek.nextclouddlna.util
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import kotlin.reflect.KClass
interface Logging {
val logger: Logger
get() = LoggerFactory.getLogger(classNameOf(this::class))
}
fun classNameOf(ownerClass: KClass<*>): String =
if (ownerClass.isCompanion) ownerClass.java.enclosingClass.name else ownerClass.java.name

View file

@ -1,6 +1,7 @@
package net.schowek.nextclouddlna.util
import jakarta.annotation.PostConstruct
import mu.KLogging
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
import java.net.*
@ -10,7 +11,7 @@ import java.util.*
class ServerInfoProvider(
@param:Value("\${server.port}") val port: Int,
@param:Value("\${server.interface}") private val networkInterface: String
) : Logging {
) {
var address: InetAddress? = null
@PostConstruct
@ -35,4 +36,6 @@ class ServerInfoProvider(
throw RuntimeException(e)
}
}
companion object : KLogging()
}