5

I have a kotlin file with a couple of package-level functions and without any class. I would like to add logging to this class but struggle to find an elegant way to give the logger an identifier.

This is an example

package com.example.myproject.my_package

import org.slf4j.LoggerFactory


private val log = LoggerFactory.getLogger("com.example.myproject.my_package")

fun bla(term: String) {
   log.info("invoked with $term")
}

There are very good best practices to use classes to find a good identifier: link 1 link 2. What's the approach if there are no classes?

I would like to avoid writing the identifier by hand and adjust it when the package name changes. Is there a way to get the package name in kotlin?

Rylander
  • 19,449
  • 25
  • 93
  • 144
linqu
  • 11,320
  • 8
  • 55
  • 67
  • Top-level functions are good when they are utility functions. But logic should be located in a `class` (or `object`). – Miha_x64 Jul 27 '17 at 10:00
  • 1
    why that? object oriented programming is only one way to develop your code, there are other paradigm that kotlin perfectly is suited for. – linqu Jul 27 '17 at 10:28
  • 3
    Have you tried https://github.com/MicroUtils/kotlin-logging ? – Frank Schmitt Jul 27 '17 at 11:25
  • That's not because of OOP paradigm. (By the way, Singleton, which `object` stands for, is a procedural pattern.) That's because your functions are gathered in a file, which is not a fully-functional scope — it has no representation in a programming language. – Miha_x64 Jul 27 '17 at 11:55
  • @FrankSchmitt perfect, works like a charm! – linqu Jul 28 '17 at 10:28

2 Answers2

10

This line should do the job:

private val log = LoggerFactory.getLogger(object{}::class.java.`package`.name)

The object is doing nothing but nevertheless kotlin will create a class to hold the code. You can then access the class, the package, the package name.

Note the usage of backtick because package is a reserved keyword. In java it is not a problem because the real method is getPackage(). The shorter syntax of kotlin transform this method call by a direct access to the property which name now collides with reserved keywords.

GaetanZ
  • 2,819
  • 3
  • 21
  • 20
  • Great answer, thanks. Finally I went with the solution given by Frank's comment. If you are fine with this extra dependency his solution is even more elegant. – linqu Jul 30 '17 at 13:47
  • 1
    Of course, I was more focused on your precise question "Is there a way to get the package name in kotlin?" than what I would do myself. – GaetanZ Jul 30 '17 at 17:37
4

You can create a top-level logger for the generated class like this:

private val logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass())

Or for the package like this:

private val logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass().`package`.name)

This has the benefit of not creating an additional class file but it requires atleast Java 7. I have created a library which assists with this and more at https://github.com/kxtra/kxtra-slf4j.

hunterwb
  • 201
  • 2
  • 4