Logging operations in lightadmin - java

I have a Java web application which use Spring and Hibernate and I plan to use lightadmin to provide an administration interface.
However, I found very little information about the logging part of lightadmin : if I have such an adminsitration interface, I would like that any operation made to our data (such as create, update or delete) is logged in our custom logger (it's not on a file but on a table on the database, this choice has already been made and implemented long time ago).
My need is to have a log entry containing some information (might be just the id) about the modified rows. Is there a global way to configure it?
Or can I add a logging annotation somewhere in each class which extends AdministrationConfiguration? If yes, where?

You can use the class AbstractRepositoryEventListener like it's show on the LightAdmin documentation here
Add you logger insertion by overiding onAfterSave, onAfterCreate and onAfterDelete into your own RepositoryEventListener.
After you just need to register your listener like this
public class YourAdministration extends AdministrationConfiguration<YourObject> {
public EntityMetadataConfigurationUnit configuration(EntityMetadataConfigurationUnitBuilder configurationBuilder) {
return configurationBuilder
.repositoryEventListener(YourRepositoryEventListener.class)
.build();
}
}

Related

Mandatory Flush for a repository

Situation: JPA, SpringBoot, Hibernate
public interface ViewRepository
extends JpaRepository<SomeView, Long>, JpaSpecificationExecutor<SomeView> {
Optional<SomeView> findByIdAndLanguageId(Long id,Long lid);
}
//service
SomeView getSomeView(){
SomeView someView1 = repo.findByIdAndLanguageId(id,lid1);
....
//now get in it in different lang id
SomeView someView2 = repo.findByIdAndLanguageId(id,lid2);
//the problem here is that the value for someView2is the same as someView1 since hibernate cash this.
}
Is there an annotation / way to prevent this caching for any call to this repository only?(not application wide turning of the caching) at service level or repository level ....
This is main feature of Hibernate.
If you look something up and change new found entity, changes will be saved to database without any additional code.
If you don't want that you need to use thing called "stateless session". But please warn everyone around about it, because otherwise you end up with many surprised people. This "stateless session" isn't very popular thing and no one will expect you use it.
If you don't want this caching to happen, you can immediately detach the entity after reading it i.e.:
SomeView someView1 = repo.findByIdAndLanguageId(id,lid1);
entityManager.detach(someView1);

Description on JMX fields and methods JBoss

How can we add description on the fields and operations exposed for JMX?
JBoss version : JBoss EAP 5.1.2
We have a Service bean as
#Service
#Management(MyConfigMgnt.class)
public class MyConfigService implements MyConfigLocal, MyConfigMgnt {
public void setMyValue(String MyValue){}
public String getMyValue(){}
}
These methods are declared in the MyConfigMgnt interface.
This is visible in the jboss jmx console as
and for the field it is shown as
How do we add relevant and proper information on the fields and the MBean.
Thanks
There's 2 ways of doing this.
Re-implement your service as a DynamicMBean which is slightly more complicated but allows for the definition of attribute and operation meta-data. (i.e. MyConfigMgnt extends DynamicMBean)
An easier way (but possibly not future-proof) is to use an XMBean descriptor. XMBeans are a proprietary JBoss JMX extension where meta-data is defined in an external XML resource. It would require no actual changes to the source code except the addition of the XMBean resource location which looks something like this:
#Service(objectName = XMBeanService.OBJECT_NAME, xmbean = "resource:META-INF/service-xmbean.xml")
If you have a very large number of attributes and operations, the XMBean XML descriptor can be arduous to write, but twiddle has a helper command which will generate a template specific to your existing simple MBean, so you can save the output, fill in the details and go from there.

use conditional logging via domino api

I want to implement the logging to openlog.nsf functionality from the domino api in an application.
However in the current setup of the application logging (to Domino console) only occurs when this is enabled for the whole application via a configuration property e.g.
public static void writeToConsole(String msg){
if (getDeugMode() ==true) {
System.out.println(msg);
}
}
usage:
writeToConsole("hello world");
I am wondering how I could rewrite the writeToConsole method to utilize the XspOpenLogLogUtil class?
XspOpenLogUtil.logErrorEx(Throwable, String, Level, Document) will allow you to pass a custom message.
Also XspOpenLogUtil.getOpenLogItem() gets a handle on the OpenLogItem object. From there you can use any of the inner methods.
See this page https://wiki.openntf.org/pages/viewpage.action?pageId=6586418 (all the method names are the same, the class in ODA is just XspOpenLogUtil instead of OpenLogUtil.
In my apps I usually have a wrapper method handleException(Throwable t) which calls XspOpenLogUtil.logError()` anyway and that's what I would recommend. It gives greater flexibility for handling e.g. different logging levels like this or changing the logging framework, should you so wish in the future.

IDs for log messages when using SLF4J

I would like to add a unique identifier to log statements, so I am able to add documentation (externally, e.g. a wiki) to every log statement, so a user can quickly access the message related documentation using the id. The logging framework I would like to use is SLF4J/logback.
I was not able to find documentation about related approaches except for some bits regarding auditing frameworks.
There is the Marker concept which I thought could be usable for ID injection, or I could just add the ID to the message text itself.
How would I add IDs to the logging statements "the right way"? Are there possibilities I didn't think of?
EDIT
The term unique ID just states there should be an identifier per log statement. A developer e.g. adds such an ID to a table/enum/whatever manually, which could be done wrong.
Such ID has to be stable, so documentation can be based on it. So the ID itself is not what I am wondering about.
My question is: what would be the right way of pushing the ID to the logger together with the message text? Would Markers be suited for this kind of requirement, should I embed the ID into the message text or is there some other possibility?
So, basically, would I use
logger.info(IDMarkers.DB_CONNECTION_FAILED, "no connection to the database");
or instead just
logger.info("[{}] no connection to the database", LogIDs.DB_CONNECTION_FAILED);
First approach has the advantage that showing the IDs is up to the logging system/its configuration.
Slf4j has http://www.slf4j.org/apidocs/org/slf4j/Marker.html
Unfortunately Markers are advertised for a different purpose. Still you can use them to uniquely mark logging statements.
More cumbersome solution is MDC:
MDC.put("MsgId", "EV-1234");
log.info()
MDC.remove("MsgId");
or with structural logging (requires v2.0.0):
logger.atDebug()
.addKeyValue("MsgId", "EV-1234")
.log("Temperature changed.");
Unique is only unique within some scope. Eventually, even every int or long value will be used.
So think about what "uniqueness" means to you. Then use a wrapper that will ensure your logging is handled with that id inserted.
Note that with slf4j you are dealing with an interface which will make a number of logging APIs consistent. This means you probably won't have the option to sub-class or even inject your implementation of the interface to ensure your consistent logging. Therefore you will be constrained to techniques like wrapping your logging API (preferably through the "consistent" interface).
package mypackage.log;
public class LoggerWrapper implements org.log4j.Logger {
private org.log4j.Logger logger;
public LoggerWrapper(org.log4j.Logger logger) {
this.logger = logger;
}
public String getUniqueId() {
return ...;
}
public void info(String message, Object params...) {
logger.info(String.format("[%d] %s", getUniqueId(), message), params));
}
... implement all the other methods ...
}
And this means that you will have to make your own LoggerFactory interface too
public Logger getLogger(String name) {
return new LoggerWrapper(org.sql4j.LoggerFactory(name));
}
While the code above has a few warts (not actually testing it); hopefully, it will give you an idea.

Separate INFO and ERROR logs from java.util.logging

I'm configuring the logging for a Java application. What I'm aiming for is two logs: one for all messages and one for just messages above a certain level.
The app uses the java.util.logging.* classes: I'm using it as is, so I'm limited to configuration through a logging.properties file.
I don't see a way to configure two FileHandlers differently: the docs and examples I've seen set properties like:
java.util.logging.FileHandler.level = INFO
While I want two different Handlers logging at different levels to different files.
Any suggestions?
http://java.sun.com/j2se/1.4.2/docs/guide/util/logging/overview.html is helpful. You can only set one Level for any individual logger (as you can tell from the setLevel() method on the logger). However, you can take the lowest of the two common levels, and then filter programmatically.
Unfortunately, you can't do this just with the configuration file. To switch with just the configuration file you would have to switch to something like log4j, which you've said isn't an option.
So I would suggest altering the logging in code, with Filters, with something like this:
class LevelFilter implements Filter {
private Level Level;
public LevelFilter(Level level) {
this.level = level;
}
public boolean isLoggable(LogRecord record) {
return level.intValue() < record.getLevel().intValue();
}
}
And then on the second handler, do setFilter(new LevelFilter(Level.INFO)) or whatever. If you want it file configurable you could use a logging properties setting you've made up yourself, and use the normal Properties methods.
I think the configuration code for setting up the two file handlers ad the programmatic code is fairly simple once you have the design, but if you want more detail add a comment and I'll edit.
I think you should be able to just subclass a handler and then override the methods to allow output to go to multiple files depending on the level of the message. This would be done by overriding the publish() method.
Alternatively, if you have to use the system-provided FileHandler, you could do a setFilter() on it to inject your own filter into the mix and, in that filter code, send ALL messages to your other file and return true if the LogRecord level if INFO or higher, causing the FileHandler.publish() to write it to the real file.
I'm not sure this is the way you should be using filters but I can't see why it won't work.

Categories