Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Declaring logger outside the class vs. inside #364

Closed
djkeh opened this issue Oct 12, 2023 · 8 comments
Closed

Declaring logger outside the class vs. inside #364

djkeh opened this issue Oct 12, 2023 · 8 comments

Comments

@djkeh
Copy link

djkeh commented Oct 12, 2023

According to the doc:

https://github.com/oshai/kotlin-logging#getting-started

This seems to be the official way to set up the logger.

import io.github.oshai.kotlinlogging.KotlinLogging

private val logger = KotlinLogging.logger {} // logger outside the class scope

class FooWithLogging {
    val message = "world"
    fun bar() {
        logger.debug { "hello $message" }
    }
}

The point is that the logger stands outside the class.
There is a fair reason as well looking at this wiki page:

https://github.com/oshai/kotlin-logging/wiki#obtaining-a-logger

My question is, what is the practical difference between putting the logger outside the class and putting it inside?
The code below still seems to work.

import io.github.oshai.kotlinlogging.KotlinLogging

class FooWithLogging {
    private val logger = KotlinLogging.logger {} // logger inside the class scope
    val message = "world"
    fun bar() {
        logger.debug { "hello $message" }
    }
}

Actually, the latter style seems to be more preferred to the conventional java developers including my coworkers.
For the practical view, they say it was uncomfortable when trying to duplicate the original class code to start over,
as intellij was not able to copy the logger line outside the class, like the image below:

image

It is also a very common and de-facto standard java code convention that a file contains a single class.
I'm afraid the former style violates this convention, it's not java but kotlin though.
I also think that making the logger static wouldn't be such a big deal. It is a singleton object already.

So going back to the question,
what is the difference between putting the logger outside the class and putting it inside?
And what should we use? Which is the better way?
What side effects are expected other than the explanation from wiki if we put the logger property inside the class?

Reference

@github-actions
Copy link

Thank you for reporting an issue. See the wiki for documentation and slack for questions.

@recursive-rat4
Copy link

Kotlin doesn't support static members yet, for details you can see KEEP-348.

@DanielGolan-mc
Copy link

DanielGolan-mc commented Oct 13, 2023

class MyClass {
    companion object {
        internal val logger = KotlinLogging.logger { }
    }
}

This is a semi-static variation of what you want. Using private here won't allow the class to use the logger, and using internal allows the entire project to use this logger. So for now, declare the logger outside of the class. Shouldn't turn your class's file icon into the kotlin symbol instead of a class icon if you care about that.

In my own library, I just turned the loggers into a part of some classes' lifecycles.

@djkeh
Copy link
Author

djkeh commented Oct 16, 2023

Thank you for the opinions. The common idea on the ground seems that the logger should be static. We need to think about this.

  1. Like I said, it may not necessarily be static. What is the traditional purpose of being static? What I know is that we need only one logger, and we don't want to create it twice. And it is ALREADY one, it is created via object, so it is singleton. It will never be created twice in the name of kotlin.
  2. The performance between the approach to get the only instance from singleton and from the static is controversial nowadays, more and more people believe singleton logger is fast enough compared to the static logger. Some people even believe the instance is now faster than the static object. The logger instance in the heap memory also has some benefits that the static logger doesn't.
  3. The second important view is that, it still works anyway if you put it in the class property. It can be considered as another traditional pattern as well to put logger in the source code. So why is it considered bad and should be avoided? I believe we need clearer reason not to put it inside the class other than "to make it static".

ps. @DanielGolan-mc You are right, I don't want to put it in the companion object, either. It sucks.

@oshai
Copy link
Owner

oshai commented Oct 16, 2023

We wanted to have one instance of logger per class / file (and not per instance of the class). In order to do that there are few options:

  • outside of the class.
  • in an object / companion object.

Initially both options were available, but in order to have one standard way we decided to recommend only the outside of the class style. It makes some sense to have a logger per file in most cases.

So where to put the declaration is mostly a style thing, and the style we chose is to have it outside of the class.
Other options are still possible to some extent.
Hope that clarifies things.

@djkeh
Copy link
Author

djkeh commented Oct 17, 2023

Thanks @oshai , I think that clarifies things enough.
I think the current style is good enough for the standard of kotlin-logging.
I'd just like to ask an additional question before closing this issue.

What if we allow a logger per instance of the class as the standard style?
There are some benefits that comes out of my head:

  1. We can stick to the java convention, which states that a file contains a class. This idea is not mandatory on the kotlin side though.
  2. We can have a bit smoother IDE support in the situations like duplicating source codes.
  3. There would be no confusion between loggers in the files that shares the same package names.
com
└── me
    └── example
        └── service
            ├── MyExample1.kt
            └── MyExample2.kt

In this example above, the full names of the logger fields would be: com.me.example.service.logger,
and these loggers serves different classes, in this case MyExample1 and MyExample2.

@oshai
Copy link
Owner

oshai commented Oct 18, 2023

What if we allow a logger per instance of the class as the standard style?

This is inefficient in terms of memory usage (additional pointer for each instance) so not recommended. Also in java it's usually static.
You can still do it, but it's not going to be the recommendation.

@djkeh
Copy link
Author

djkeh commented Oct 20, 2023

Thanks for the explanation. I close this issue now.

@djkeh djkeh closed this as completed Oct 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants