How to define logging in one place in Python? - java

I am new Python and I want to define the following logging code in python in one place so that it can be used in other python files(class or non-class). In case of Java, we use log4j or slf4j as part of jar files and we simply define as Logger logger = Logger.getLogger("class name"), I want achieve exactly like this so that I can use loger in any python module/s. Currently I define the config in all the classes.
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.FileHandler("debug.log"),
logging.StreamHandler()
]
)
I have also gone through this SO link Using logging in multiple modules
Also please suggest the most recommended approach for medium to large project having more number of python files.

As per this link https://fangpenlin.com/posts/2012/08/26/good-logging-practice-in-python/, the author has mentioned a better practice. There may be better recommended approach.
You have to do in the following manner.
Define logging.json file as mentioned in the link.
Define a python file called LogSetup.py and add below the code.
def setup_logging(default_path='logging.json', default_level=logging.DEBUG, env_key='LOG_CFG'):
"""Setup logging configuration"""
path = default_path
value = os.getenv(env_key, None)
if value:
path = value
if os.path.exists(path):
with open(path, 'rt') as f:
config = json.load(f)
logging.config.dictConfig(config)
else:
logging.basicConfig(level=default_level)
Call the above file like this LogSetup.setup_logging() in the main method.
I provide below the code snippet.
logger = logging.getLogger(name)
if __name__ == '__main__':
LogSetup.setup_logging()
logger.debug("This is a debug message ...")
It looks good for me, others may recommend the better approaches.

One option to make your logging handler available everywhere, is to make it a built-in identifier:
a.py:
import logging
import builtins
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(filename)s [%(levelname)s] %(message)s",
handlers=[
logging.FileHandler("/tmp/debug.log"),
logging.StreamHandler()
]
)
builtins.logger = logging.getLogger(__name__)
logger.info("module a!")
import b
b.py:
logger.info(msg='This is from module b.py')
def foo():
logger.info('Log message from b.foo()')
foo()
Output:
2020-02-14 20:18:17,549 a.py [INFO] module a!
2020-02-14 20:18:17,550 b.py [INFO] This is from module b.py
2020-02-14 20:18:17,550 b.py [INFO] Log message from b.foo()

Related

Getting a "Using type x from an indirect dependency" in java_test_suite even when x is declared under dependency

My CustomTest.java has this import:
com.google.protobuf.Timestamp
I'm using java_test_suite to run tests in my BUILD file like so:
java_test_suite(
name = "all-tests",
srcs = glob(["src/test/java/**/*.java"]),
runner = "junit5",
test_suffixes = ["Test.java"],
runtime_deps = JUNIT5_DEPS,
deps = [
":mylib",
"#com_google_protobuf//:timestamp_proto",
artifact("org.junit.jupiter:junit-jupiter-api"),
artifact("org.junit.jupiter:junit-jupiter-params"),
] + deps,
)
However when I run tests on it using:
bazel test //:all-tests
I'm getting this error:
src/test/java/com/x/CustomTest.java:75: error: [strict] Using type com.google.protobuf.Timestamp from an indirect dependency (TOOL_INFO: "#com_google_protobuf//:timestamp_proto wrapped in java_proto_library"). See command below **
private static Timestamp timestampFromMilli(long milli) {
^
** Please add the following dependencies:
#com_google_protobuf//:timestamp_proto to //:src/test/java/com/x/CustomTest
** You can use the following buildozer command:
buildozer 'add deps #com_google_protobuf//:timestamp_proto' //:src/test/java/com/x/CustomTest
What do I need to do exactly? I tried using the buildozer command but all I got was:
rule 'src/test/java/com/x/CustomTest' not found
Where do I need to add this #com_google_protobuf//:timestamp_proto?
Looking at protobuf's build files, it looks like timestamp_proto is a plain proto_library:
https://github.com/protocolbuffers/protobuf/blob/main/BUILD.bazel#L70-L74
https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/BUILD.bazel#L64-L68
and so per the advice here:
https://github.com/protocolbuffers/protobuf/blob/main/BUILD.bazel#L19-L25
you might just need to use java_proto_library to make the java version of the proto:
java_proto_library(
name = "timestamp_java_proto",
deps = ["#com_google_protobuf//:timestamp_proto"],
)
and then use that in the deps of your java_test_suite instead of the timestamp_proto.
Just a guess, but the error message is not very helpful maybe because there happens to be a Timestamp java class in the deps of the plain proto library, and Strict deps is finding that one in the test's indirect dependencies. Might be worth filing a bug about it on https://github.com/bazelbuild/bazel/issues

How to: generate .so file using rules_go in bazel on windows

I've switched (or, am in the process of switching) to using bazel, though I'm doing so on Windows.
I'm interested in calling into my Go code from Java, so I started with this tutorial.
I was able to make that work using the same code as on their Github example and everything works fine. I tried adapting that to my bazel build. If I take the awesome.so file generated by go build -o awesome.so -buildmode=c-shared awesome.go and include it as a resource to my java_library, I can make everything work.
Relevant files shown below.
Ideally, however, I'd like to have everything generated through bazel, but despite all my attempts thus far my go_binary rule always outputs awesome.a (and awesome.x). If I switch to using //go:awesome as the resource from java:client_lib I am able to successfully see the awesome.a output as a resource, which suggests that getting my go_binary to output awesome.so is the last piece of the puzzle, but the correct combination of flags has thus far eluded me.
Basically I just want to make my go_binary rule have the same behavior as running go build -o awesome.so --buildmode=c-shared awesome.go.
In theory I'm ok if I need another rule to bridge the gap, but since I'm on windows and bash has been hit or miss thus far, using genrule as the intermediate doesn't currently look promising.
Please advise, and thanks!
WORKSPACE
...
# bazelbuild/rules_go for golang support.
http_archive(
name = "io_bazel_rules_go",
sha256 = "b725e6497741d7fc2d55fcc29a276627d10e43fa5d0bb692692890ae30d98d00",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.24.3/rules_go-v0.24.3.tar.gz",
"https://github.com/bazelbuild/rules_go/releases/download/v0.24.3/rules_go-v0.24.3.tar.gz",
],
)
load("#io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
go_rules_dependencies()
go_register_toolchains()
...
go/awesome.go is copied from the article.
go/BUILD
load("#io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
package(default_visibility = ["//visibility:public"])
go_binary(
name = "awesome",
srcs = glob(["*.go"]),
cgo = True,
copts = [
"-fPIC", # I tried adding this after some other reading about .a->.so
],
gc_linkopts = [
"-shared", # I think this is equivalent to the linkmode=c-shared below, but... <shrug>
],
linkmode = "c-shared",
static = "off",
)
# This one uses the pre-built awesome.so, and this works.
filegroup(
name = "prebuilt_awesome_resource",
srcs = ["awesome.so"],
)
java/Client.java is copied from the github repo linked in the article (with slight tweaks to the library's location).
java/BUILD
package(default_visibility = ["//visibility:public"])
java_import(
name = "jna",
jars = ["jna.jar"],
)
java_library(
name = "client_lib",
srcs = glob(["*.java"]),
resources = [
# "//go:awesome", # I'd rather use this one.
"//go:prebuilt_awesome_resource",
],
deps = [
":jna",
],
)
java_binary(
name = "client",
main_class = "Client",
runtime_deps = [
":client_lib",
],
)
and also, since it was important getting go stuff to run:
%programdata%/basel.bazelrc
startup --output_user_root="C:/_bazel_out"
build --compiler=mingw-gcc
Well, I guess I need to go sit in the shame cube for a while.
Of all the options I was looking at for the compiler I missed checking other attributes on go_binary. Specifically, the obvious one, out. The one that actually corresponds to the -o flag on go build
I added out = "awesome.so" to my go_binary rule and, sure enough, everything works.
Well that's a few hours wasted. Thanks Jay for trying to help and sorry for asking a dumb question.
This might not answer your question exactly, but I can give an example of calling a Go shared library from a C program on macOS. Hopefully that gets you most of the way there.
For the go_binary, you just need linkmode = "c-shared". You'll also need cgo = True for each package that either contains cgo code or has exported definitions. You don't need -shared, -fPIC, or static = "off".
Exported definitions should be marked with an //export comment.
There's an implicitly declared target with the suffix .c_hdrs that builds a header file for the Go library. It's :go_hello.c_hdrs in the example below. The actual header file name is go_hello.h, matching the target name.
You need to wrap the generated files with a cc_import rule to make it usable as a C/C++ dependency. #2433 is an open issue to streamline that process, but it's only recently possible in Bazel.
Anything that can consume a cc_library can consume the cc_import target the same way. So you should be able to call Go functions via JNI, though I've never tried that out.
BUILD.bazel
load("#io_bazel_rules_go//go:def.bzl", "go_binary")
go_binary(
name = "go_hello",
srcs = ["hello.go"],
cgo = True,
linkmode = "c-shared",
)
cc_import(
name = "c_hello",
hdrs = [":go_hello.c_hdrs"],
shared_library = ":go_hello",
)
cc_binary(
name = "use",
srcs = ["use.c"],
deps = [":c_hello"],
)
hello.go
package main
import "fmt"
import "C"
//export SayHello
func SayHello() {
fmt.Println("hello")
}
func main() {}
use.c
#include "go_hello.h"
int main() {
SayHello();
return 0;
}

Error reading image from scala playn

I researched and looked into the PlayN game framework and I liked it a lot. I program in Scala and actually don't know Java but it's not usually a problem since they work together great.
I've set up a basic project in eclipse and imported all the libraries and dependencies. I even translated over the base maven project code. Here's the two files:
Zeitgeist.scala
package iris.zeit.core
import playn.core.PlayN._
import playn.core.Game
import playn.core.Image
import playn.core.ImageLayer
class Zeitgeist extends Game {
override def init (){
var bgImage: Image = assets().getImage("images/bg.png")
var bgLayer: ImageLayer = graphics().createImageLayer(bgImage)
graphics().rootLayer().add(bgLayer)
}
override def paint (alpha: Float){
//painting stuffs
}
override def update(delta: Float){
}
override def updateRate(): Int = {
25
}
}
Main.scala
package iris.zeit.desktop
import playn.core.PlayN
import playn.java.JavaPlatform
import iris.zeit.core.Zeitgeist
object Main {
def main(args: Array[String]){
var platform: JavaPlatform = JavaPlatform.register()
platform.assets().setPathPrefix("resources")
PlayN.run(new Zeitgeist())
}
}
The cool thing is it works! A window comes up perfectly. The only problem is I can't seem to load images. With the above line, "assets().getImage("images/bg.png")" it pops out
Could not load image: resources/images/bg.png [error=java.io.FileNotFoundException: resources/images/bg.png]
I've played around with the location of my resources file to no avail. I was even able to find bg.png myself with java.io.File. Am I doing something wrong? Is there something I'm forgetting?
Looking at the code of JavaAssetsManager, it looks like it is trying to load a resource and not a file. So you should check that your images are actually in the classpath and at the path you give ("resources/images/bp.png")
Alternatively, you can use getRemoteImage and pass a File URL. As you succeeded in using a java.io.File, you can just get the URL with method toUri of File (toUrl is deprecated).
This almost certainly doesn't work because you're doing this:
platform.assets().setPathPrefix("resources")
That means you're saying your source folder looks like this:
src/main/resources/resources/images/bg.png
src/main/resources/resources/images/pea.png
src/main/resources/resources/images
I imagine it actually looks like one of these:
src/main/resources/assets/images/bg.png <-- 'assets' the default prefix
src/main/resources/assets/images/pea.png
src/main/resources/assets/images
or:
src/main/resources/images/bg.png <-- You have failed to put a subfolder prefix in
src/main/resources/images/pea.png
src/main/resources/images
You can either do this, if you have no prefix:
plat.assets().setPathPrefix("")
Or just put your files in the assets sub-folder inside the resources folder.
It's worth noting that the current implementation calls:
getClass().getClassLoader().getResource(...)
Not:
getClass().getResource(...)
The difference is covered elsewhere, but the tldr is that plat.assets.getImage("images/pea.png") will work, but plat.assets.getImage("/images/pea.png") will not.

Calling clojure from java

Most of the top google hits for "calling clojure from java" are outdated and recommend using clojure.lang.RT to compile the source code. Could you help with a clear explanation of how to call Clojure from Java assuming you have already built a jar from the Clojure project and included it in the classpath?
Update: Since this answer was posted, some of the tools available have changed. After the original answer, there is an update including information on how to build the example with current tools.
It isn't quite as simple as compiling to a jar and calling the internal methods. There do seem to be a few tricks to make it all work though. Here's an example of a simple Clojure file that can be compiled to a jar:
(ns com.domain.tiny
(:gen-class
:name com.domain.tiny
:methods [#^{:static true} [binomial [int int] double]]))
(defn binomial
"Calculate the binomial coefficient."
[n k]
(let [a (inc n)]
(loop [b 1
c 1]
(if (> b k)
c
(recur (inc b) (* (/ (- a b) b) c))))))
(defn -binomial
"A Java-callable wrapper around the 'binomial' function."
[n k]
(binomial n k))
(defn -main []
(println (str "(binomial 5 3): " (binomial 5 3)))
(println (str "(binomial 10042 111): " (binomial 10042 111)))
)
If you run it, you should see something like:
(binomial 5 3): 10
(binomial 10042 111): 49068389575068144946633777...
And here's a Java program that calls the -binomial function in the tiny.jar.
import com.domain.tiny;
public class Main {
public static void main(String[] args) {
System.out.println("(binomial 5 3): " + tiny.binomial(5, 3));
System.out.println("(binomial 10042, 111): " + tiny.binomial(10042, 111));
}
}
It's output is:
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263
The first piece of magic is using the :methods keyword in the gen-class statement. That seems to be required to let you access the Clojure function something like static methods in Java.
The second thing is to create a wrapper function that can be called by Java. Notice that the second version of -binomial has a dash in front of it.
And of course the Clojure jar itself must be on the class path. This example used the Clojure-1.1.0 jar.
Update: This answer has been re-tested using the following tools:
Clojure 1.5.1
Leiningen 2.1.3
JDK 1.7.0 Update 25
The Clojure Part
First create a project and associated directory structure using Leiningen:
C:\projects>lein new com.domain.tiny
Now, change to the project directory.
C:\projects>cd com.domain.tiny
In the project directory, open the project.clj file and edit it such that the contents are as shown below.
(defproject com.domain.tiny "0.1.0-SNAPSHOT"
:description "An example of stand alone Clojure-Java interop"
:url "http://clarkonium.net/2013/06/java-clojure-interop-an-update/"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]]
:aot :all
:main com.domain.tiny)
Now, make sure all of the dependencies (Clojure) are available.
C:\projects\com.domain.tiny>lein deps
You may see a message about downloading the Clojure jar at this point.
Now edit the Clojure file C:\projects\com.domain.tiny\src\com\domain\tiny.clj such that it contains the Clojure program shown in the original answer. (This file was created when Leiningen created the project.)
Much of the magic here is in the namespace declaration. The :gen-class tells the system to create a class named com.domain.tiny with a single static method called binomial, a function taking two integer arguments and returning a double. There are two similarly named functions binomial, a traditional Clojure function, and -binomial and wrapper accessible from Java. Note the hyphen in the function name -binomial. The default prefix is a hyphen, but it can be changed to something else if desired. The -main function just makes a couple of calls to the binomial function to assure that we are getting the correct results. To do that, compile the class and run the program.
C:\projects\com.domain.tiny>lein run
You should see output shown in the original answer.
Now package it up in a jar and put it someplace convenient. Copy the Clojure jar there too.
C:\projects\com.domain.tiny>lein jar
Created C:\projects\com.domain.tiny\target\com.domain.tiny-0.1.0-SNAPSHOT.jar
C:\projects\com.domain.tiny>mkdir \target\lib
C:\projects\com.domain.tiny>copy target\com.domain.tiny-0.1.0-SNAPSHOT.jar target\lib\
1 file(s) copied.
C:\projects\com.domain.tiny>copy "C:<path to clojure jar>\clojure-1.5.1.jar" target\lib\
1 file(s) copied.
The Java Part
Leiningen has a built-in task, lein-javac, that should be able to help with the Java compilation. Unfortunately, it seems to be broken in version 2.1.3. It can't find the installed JDK and it can't find the Maven repository. The paths to both have embedded spaces on my system. I assume that is the problem. Any Java IDE could handle the compilation and packaging too. But for this post, we're going old school and doing it at the command line.
First create the file Main.java with the contents shown in the original answer.
To compile java part
javac -g -cp target\com.domain.tiny-0.1.0-SNAPSHOT.jar -d target\src\com\domain\Main.java
Now create a file with some meta-information to add to the jar we want to build. In Manifest.txt, add the following text
Class-Path: lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar
Main-Class: Main
Now package it all up into one big jar file, including our Clojure program and the Clojure jar.
C:\projects\com.domain.tiny\target>jar cfm Interop.jar Manifest.txt Main.class lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar
To run the program:
C:\projects\com.domain.tiny\target>java -jar Interop.jar
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263
The output is essentially identical to that produced by Clojure alone, but the result has been converted to a Java double.
As mentioned, a Java IDE will probably take care of the messy compilation arguments and the packaging.
As of Clojure 1.6.0, there is a new preferred way to load and invoke Clojure functions. This method is now preferred to calling RT directly (and supersedes many of the other answers here). The javadoc is here - the main entry point is clojure.java.api.Clojure.
To lookup and call a Clojure function:
IFn plus = Clojure.var("clojure.core", "+");
plus.invoke(1, 2);
Functions in clojure.core are automatically loaded. Other namespaces can be loaded via require:
IFn require = Clojure.var("clojure.core", "require");
require.invoke(Clojure.read("clojure.set"));
IFns can be passed to higher order functions, e.g. the example below passes plus to read:
IFn map = Clojure.var("clojure.core", "map");
IFn inc = Clojure.var("clojure.core", "inc");
map.invoke(inc, Clojure.read("[1 2 3]"));
Most IFns in Clojure refer to functions. A few, however, refer to non-function data values. To access these, use deref instead of fn:
IFn printLength = Clojure.var("clojure.core", "*print-length*");
IFn deref = Clojure.var("clojure.core", "deref");
deref.invoke(printLength);
Sometimes (if using some other part of the Clojure runtime), you may need to ensure that the Clojure runtime is properly initialized - calling a method on the Clojure class is sufficient for this purpose. If you do not need to call a method on Clojure, then simply causing the class to load is sufficient (in the past there has been a similar recommendation to load the RT class; this is now preferred):
Class.forName("clojure.java.api.Clojure")
EDIT This answer was written in 2010, and worked at that time. See Alex Miller's answer for more modern solution.
What kind of code are calling from Java? If you have class generated with gen-class, then simply call it. If you want to call function from script, then look to following example.
If you want to evaluate code from string, inside Java, then you can use following code:
import clojure.lang.RT;
import clojure.lang.Var;
import clojure.lang.Compiler;
import java.io.StringReader;
public class Foo {
public static void main(String[] args) throws Exception {
// Load the Clojure script -- as a side effect this initializes the runtime.
String str = "(ns user) (defn foo [a b] (str a \" \" b))";
//RT.loadResourceScript("foo.clj");
Compiler.load(new StringReader(str));
// Get a reference to the foo function.
Var foo = RT.var("user", "foo");
// Call it!
Object result = foo.invoke("Hi", "there");
System.out.println(result);
}
}
EDIT: I wrote this answer almost three years ago. In Clojure 1.6 there is a proper API exactly for the purpose of calling Clojure from Java. Please Alex Miller's answer for up to date information.
Original answer from 2011:
As I see it, the simplest way (if you don't generate a class with AOT compilation) is to use clojure.lang.RT to access functions in clojure. With it you can mimic what you would have done in Clojure (no need to compile things in special ways):
;; Example usage of the "bar-fn" function from the "foo.ns" namespace from Clojure
(require 'foo.ns)
(foo.ns/bar-fn 1 2 3)
And in Java:
// Example usage of the "bar-fn" function from the "foo.ns" namespace from Java
import clojure.lang.RT;
import clojure.lang.Symbol;
...
RT.var("clojure.core", "require").invoke(Symbol.intern("foo.ns"));
RT.var("foo.ns", "bar-fn").invoke(1, 2, 3);
It is a bit more verbose in Java, but I hope it's clear that the pieces of code are equivalent.
This should work as long as Clojure and the source files (or compiled files) of your Clojure code is on the classpath.
I agree with clartaq's answer, but I felt that beginners could also use:
step-by-step information on how to actually get this running
information that's current for Clojure 1.3 and recent versions of leiningen.
a Clojure jar that also includes a main function, so it can be run standalone or linked as a library.
So I covered all that in this blog post.
The Clojure code looks like this:
(ns ThingOne.core
(:gen-class
:methods [#^{:static true} [foo [int] void]]))
(defn -foo [i] (println "Hello from Clojure. My input was " i))
(defn -main [] (println "Hello from Clojure -main." ))
The leiningen 1.7.1 project setup looks like this:
(defproject ThingOne "1.0.0-SNAPSHOT"
:description "Hello, Clojure"
:dependencies [[org.clojure/clojure "1.3.0"]]
:aot [ThingOne.core]
:main ThingOne.core)
The Java code looks like this:
import ThingOne.*;
class HelloJava {
public static void main(String[] args) {
System.out.println("Hello from Java!");
core.foo (12345);
}
}
Or you can also get all the code from this project on github.
This works with Clojure 1.5.0:
public class CljTest {
public static Object evalClj(String a) {
return clojure.lang.Compiler.load(new java.io.StringReader(a));
}
public static void main(String[] args) {
new clojure.lang.RT(); // needed since 1.5.0
System.out.println(evalClj("(+ 1 2)"));
}
}
If the use case is to include a JAR built with Clojure in a Java application, I have found having a separate namespace for the interface between the two worlds to be beneficial:
(ns example-app.interop
(:require [example-app.core :as core])
;; This example covers two-way communication: the Clojure library
;; relies on the wrapping Java app for some functionality (through
;; an interface that the Clojure library provides and the Java app
;; implements) and the Java app calls the Clojure library to perform
;; work. The latter case is covered by a class provided by the Clojure lib.
;;
;; This namespace should be AOT compiled.
;; The interface that the java app can implement
(gen-interface
:name com.example.WeatherForecast
:methods [[getTemperature [] Double]])
;; The class that the java app instantiates
(gen-class
:name com.example.HighTemperatureMailer
:state state
:init init
;; Dependency injection - take an instance of the previously defined
;; interface as a constructor argument
:constructors {[com.example.WeatherForecast] []}
:methods [[sendMails [] void]])
(defn -init [weather-forecast]
[[] {:weather-forecast weather-forecast}])
;; The actual work is done in the core namespace
(defn -sendMails
[this]
(core/send-mails (.state this)))
The core namespace can use the injected instance to accomplish its tasks:
(ns example-app.core)
(defn send-mails
[{:keys [weather-forecast]}]
(let [temp (.getTemperature weather-forecast)] ...))
For testing purposes, the interface can be stubbed:
(example-app.core/send-mails
(reify com.example.WeatherForecast (getTemperature [this] ...)))
Other technique that works also with other languages on top of JVM is to declare an interface for functions you want to call and then use 'proxy' function to create instance that implemennts them.
You can also use AOT compilation to create class files representing your clojure code. Read the documentation about compilation, gen-class and friends in the Clojure API docs for the details about how to do this, but in essence you will create a class that calls clojure functions for each method invocation.
Another alternative is to use the new defprotocol and deftype functionality, which will also require AOT compilation but provide better performance. I don't know the details of how to do this yet, but a question on the mailing list would probably do the trick.

Java logging configuration only partially taken into account

I've an issue with a project I try to deliver using the one-jar packager to simplify the deployment process.
Without the packaging, everything works fine and the logging configuration is perfectly loaded, but within the packaging, only part of the configuration is appied.
So, here is the logging.properties I use:
handlers= java.util.logging.ConsoleHandler, java.util.logging.FileHandler
.level= INFO
java.util.logging.FileHandler.pattern = C:\\MyPath\\logging.csv
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = my.package.logging.Formatter
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = my.package.logging.Formatter
And In my main class, here is how I load it:
public class MainClass {
public static void main(final String[] args) {
try {
LogManager.getLogManager().readConfiguration(
new MainClass().getClass().getResourceAsStream("logging.properties"));
// main process goes here.
} catch(Exception e) {
// Exception handling
}
}
}
The log level as well as the FileHandler pattern are well understood because the logging ends up in the correct file, but as row XML output, which makes me think that the formatter is not loaded as it normally outputs a CSV format.
Could it be related to a classpath issue? Does anyone knows how to handle this?
It could be in your jars you have more than one logging.properties file, with similar but slightly different settings. When you combine them with one-jar the order changes and one of them gets hidden. Do a "jar -tf *.jar |grep logging.properties" and see what you see.
If that doesn't work can you try unjarring the onejar result to a directory structure, and then running with the directory on the classpath instead of the jar? That will let you see if it is something to do with the jar, and actually inspect the logging.properties you have in the onejar, and see if it matches what you expect.
Use LogManager.getLogManager().readConfiguration(LogManager.class.getResourceAsStream("/logging.debug.properties"));
(note the extra slash).

Categories