Java warn / disallow method in specific package - java

I created a wrapper around Log.i.
public class MyLog {
public static int i(String tag, String message) {
//Do Stuff
return Log.i(tag, message);
}
}
Now I'd like all my consumers com.myapp.package1, com.myapp.package2, etc. to use MyLog.i instead of Log.i. Currently, we're just enforcing this by conventions and documentation. Are there more aggressive programatic ways to discourage or disable developers from calling Log.i from within certain packages?

Not within the language itself. THis is something better done by either your build system or your source control system. A lint rule would work, with your build system set to error out or your source control set to reject diffs that fail the rule.

Related

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.

How to use the log4j2 wrapper API

I do have some trouble understanding the log4j2 wrapper usage.
If you follow this link you will find attached an example using the AbstractLoggerWrapper. I just copied the following peace of code.
public class Log4j2Logger extends AbstractLogger
{
private static final String FQCN = AbstractLogger.class.getName();
private AbstractLoggerWrapper logImpl;
public Log4j2Logger(String name, String prefix, String logId, String instanceId)
{
super(name, prefix, logId, instanceId);
final AbstractLogger logger = (AbstractLogger) LogManager.getLogger(name);
this.logImpl = new AbstractLoggerWrapper(logger, name);
}
....
#Override
public void log(String message, LogLevel level)
{
logImpl.log(null, FQCN, toImplLevel(level), new SimpleMessage(createMessage(message)), null);
}
....
}
I don't understand the reason for subclassing AbstractLogger and intern using the AbstractLoggerWrapper. I actually could just remove the extend from the Log4j2Logger and encapsulate the AbstractLoggerWrapper. Do you see any reason of doing it like in the code snipped above?
Is there any way to subclass the AbstractLogger (like preferred) and just use it without the wrapper? And create it like a strategy pattern? e.g.,
LogManager.getLogger( class.getName(), Log4j2Logger.class )
Maybe this is what they tried to explain in the extending section and I don't understand it, yet. Somebody any idea how to do it?
Sincerely
Christian
Update: I missed to say, the reason why I am using the wrapper is because of an existing projekt with log4j (1.2) with a wrapper.
If you look at the documentation for AbstractLoggerWrapper:
Wrapper class that exposes the protected AbstractLogger methods to
support wrapped loggers.
You will see a clear indication as to why it is done the way Apache does it. If you instead decide to ignore the contract of the interface and go your own way, you are essentially saying
"I don't care how the library does things, I know better"
As such, you are taking on a great deal of risk, instead of using the general solution that has been provided. I sincerely doubt that you have such an esoteric environment that the library could would be insufficient.
To recap, follow the contract laid out by the library documentation.

Modify a method using Annotations

How can I change what a method is doing in Java ?
I mean, I am trying to use annotations to make the following code
#Anno1(Argument = "Option1")
public class TestClass
{
#Anno2
public void test()
{
}
}
Into
public class TestClass
{
private static StaticReference z;
public void test()
{
z.invokeToAll();
}
}
This is a very simplified example of what I am trying to do. Anno1 will have many possible combinations, but this is not my problem so far. My problem is how to add code to method test()
I am looking for a more generic solution if possible. Eg. A way to add every kind of code in the method (not just a way to .invokeToAll())
So far I am using import javax.annotation.processing.*; and I have the following code, but I don't know how to go on from there
private void processMethodAnnotations(RoundEnvironment env)
{
for (Element e : env.getElementsAnnotatedWith(Anno2.class))
{
//If it is a valid annotation over a method
if (e.getKind() == ElementKind.METHOD)
{
//What to do here :S
}else
{
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,"Not a method!", e);
}
}
}
I have found something about Java Reflection but I have not found any source to help me with what I am doing.
Obviously I extends AbstractProcessor in my code
I have found this tutorial (http://www.zdnetasia.com/writing-and-processing-custom-annotations-part-3-39362483.htm) But this concerns creating a new class, not just changing a method. and the javax.lang.model.elements do not provide any way of editing that element (which in my case represents a Method).
I hope my question is clear and inline with the rules. If not please comment and I will clarify. Thanks.
Annotation processing is the wrong way to go for you, from Wikipedia:
When Java source code is compiled,
annotations can be processed by
compiler plug-ins called annotation
processors. Processors can produce
informational messages or create
additional Java source files or
resources, which in turn may be
compiled and processed, but annotation
processors cannot modify the annotated
code itself.
People suggested to you the right way - AOP. Specifically, you can use AspectJ. "Quick result" way is (if you use Eclipse):
Install AJDT (AspectJ Development Tools)
Create an AspectJ project and add there your classes and annotations
Create Aspect:
public aspect Processor {
private StaticReference z;
pointcut generic()
// intercept execution of method named test, annotated with #Anno1
// from any class type, annotated with #Anno2
: execution(#Anno2 * (#Anno1 *).test())
// method takes no arguments
&& args ();
// here you have written what you want the method to actually do
void around () : generic() {
z.invokeToAll();
}
}
now you can execute a test and you will see that it works ;) AJDT compiles code for you automatically, so do not need any manual work to do, hope that's what you called "magic" ;)
UPDATE:
if your code in the test() method depends on the Anno1 annotation value, then inside aspect you can get class annotation for which it is executed this way:
void around () : generic() {
Annotation[] classAnnotations = thisJoinPoint.getThis().getClass().getAnnotations();
String ArgumentValue = null;
for ( Annotation annotation : classAnnotations ) {
if ( annotation instanceof Anno1 ) {
ArgumentValue = ((Anno1) annotation).Argument();
break;
}
}
if ( ArgumentValue != null && ArgumentValue.equals("Option1")) {
z.invokeToAll();
}
}
where thisJoinPoint is a special reference variable.
UPDATE2:
if you want to add System.out.println( this ) in your aspect, you need to write there System.out.println( thisJoinPoint.getThis() ), just tested and it works. thisJoinPoint.getThis() returns you "this" but not exactly; in fact this is Object variable and if you want to get any propery you need either to cast or to use reflection. And thisJoinPoint.getThis() does not provide access to private properties.
Well, now seems that your question is answered, but if I missed anything, or you get additional question/problems with this way - feel free to ask ;)
It's perfectly possible to do what you ask, although there is a caveat: relying on private compiler APIs. Sounds scary, but it isn't really (compiler implementations tend to be stable).
There's a paper that explains the procedure: The Hacker's Guide to Javac.
Notably, this is used by Project Lombok to provide automatic getter/setter generation (amongst other things). The following article explains how it does it, basically re-iterating what is said the aforementioned paper.
Well, you might see if the following boilerplate code will be useful:
public void magic(Object bean, String[] args) throws Exception {
for (Method method : bean.getClass().getDeclaredMethods()) {
if (method.isAnnotationPresent(Anno2.class)) {
// Invoke the original method
method.invoke(bean, args);
// Invoke your 'z' method
StaticReference.invokeAll();
}
}
}
As an alternative your might employ aspect oriented programming, for instance you have the AspectJ project.
I'm not sure at all if it is even possible to change the source or byte code via annotations. From what your describing it looks as if aspect oriented programming could provide a solution to your problem.
Your annotations are pretty similiar to the pointcut concept (they mark a location where code needs to be inserted) and the inserted code is close the advice concept.
Another approach would be parsing the java source file into an abstract syntax tree, modify this AST and serialize to a java compiler input.
If your class extends a suitable interface, you could wrap it in a DynamicProxy, which delegates all calls to the original methods, except the call to test.

Making simple performance modifications to an already compiled jar?

Like many log4j users, we often have debug level logging that is expensive to evaluate. So we guard those cases with code like:
if( _logger.isDebugEnabled )
_logger.debug("Interesting, my foojes are goofed up: " + getFullDetails())
However, that is uglier than a plain _logger.debug call, and sometimes the programmer doesn't realize the evaluation could be expensive.
It seems like it should be fairly simple to write a program that takes a compiled jar and guards all the _logger.debug calls with the isDebugEnabled check. We would likely be willing to accept the extra overhead of checking isDebugEnabled in all cases.
Has anyone tried this approach, or done similar post-processing of a jar?
Rather than looking at modifying the jar, I'd search for a solution using Bytecode Instrumentation. The problem will be to identify those parts of the code you want to wrap inside a .isDebugEnabled() - you will have to identify objects that are only used for log4j invocations.
Have you looked at AspectJ ? This supports aspects using bytecode weaving, and can interceptions into a previously compiled .jar file.
I believe a good solution would be that the code would be efficient as is.
Consider that log4j is deprecated. Its author itself left it as is, to avoid breaking compatibility, but he created a new one, SLF4J (http://www.slf4j.org/ ). He provides both a facade and an implementation, according to the distinction commons-logging/log4j, but without the flaws of each...
I believe that, in this new logging facility, you can send Object parameters to the logging, and that the level is evaluated before converting the Objects (to String or otherwise). The idea is to use a format string, and parameters.
Our code doesn't use slf4j, but we have utility methods that do exactly that.
It is coded roughly as follow (from memory):
public enum LogLevel {
FATAL, ERROR, WARNING, INFO, DEBUG;
public void log(Logger logger, String format, Object... parameters) {
if (isEnabled(logger)) {
logImpl(logger, String.format(format, parameters));
}
}
public boolean isEnabled(Logger logger) {
switch(this) {
case WARNING : return logger.isWarningEnabled();
case INFO : return logger.isInfoEnabled();
case DEBUG : return logger.isDebugEnabled();
default: return true;
}
}
private void logImpl(Logger logger, String message) {
switch(this) {
case WARNING : logger.warn(message);
// other cases
}
}
}
It is used as:
public void myMethod(Object param) {
LogLevel.WARNING.log(LOGGER, "What is my message ....", "myMethod", param);
}
UPDATE : If you need to call a method in the log...
One possibility is to use toString method. This is appropriate if your logging is 'technical', and will be used also when debugging.
If your logging is more functional (not targeted to the developper), I suggest to define an interface (it is functionally sound in that case, so it is useful to provide meaning) :
public interface Detailable { // the name could also suggest logging?
String getFullDetails();
}
Implement that interface in any object that need to be passed as logging object, with a complex calculation to build the log.

Categories