Is there a way to fire a trigger from System.out.println?
Asked Answered
A

4

2

This might be a very dumb question but, is there a way to fire a trigger whenever something is printed to the console in Java and listen for it somewhere else?

I have very little understanding of triggers or of the System class (or of Logger for that matter) so if there is an easier way of doing this (without triggers) please tell me so.

We are trying to use Logger to log all of our tests. Currently, we have been using the simple "System.out.println" to log everything in the console, so I was wondering whether I could fire a trigger whenever something in printed to it and then have a listener add that info to Logger.

Thanks.

Arched answered 9/2, 2012 at 21:53 Comment(2)
Wouldn't a global search for System.out.println( and replace with an appropriate Logger call be easier?Mims
No, System.out.println() MUST stay. Logger cannot replace it. Also, there is something else I will be doing with this (with DEBUG and INFO).Arched
T
8

The most direct way to do this would be

System.setOut(new PrintStream(System.out) {
  public void println(String s) {
    logger.log(s);
    super.println(s);
  }
  // override some other methods?
});
Tragic answered 9/2, 2012 at 22:28 Comment(4)
Looks interesting, but I have no idea what it is doing. Can you be more specific on the wrapper part?Arched
Perfect, that is it! Just one more thing to add: In the case that the application makes calls to System.out.println() passing in a parameter of type object (not String but some application-specific object), then one can override public void println(Object o) as well.Africanist
I think that overriding write(String) is the most efficient way to catch all the cases, but I'd need to dig in the PrintStream implementation.Tragic
Very good answer! I have written a singleton around it so that it is easier to listenPaugh
A
3

Aspect-Oriented Programming (AOP) can help you implement this behaviour.

Since you are working on Java, you can use AspectJ (one of the most mature AOP languages) to capture all the calls to System.out.println() and 'inject' your behaviour of notifying the Logger class.

Here is some sample code in AspectJ of how that would work:

pointcut somethingIsBeingLogged(): execution(public static * System.out.println());
before() : somethingIsBeingLogged() {
    // Get the context by joinPoint.getThis();
    // Notify the Logger class
}

You can actually stop the calls to System.out.println() and let only your Logger class take control. I can provide more details if you would like to take the AOP path.

Africanist answered 9/2, 2012 at 22:5 Comment(4)
If I was working by myself, I would take your path. Problem is that the manager wants to keep things as native as possible (he wants us to go through every file and do it manually). So I'm looking for a way to just modify the main abstract class (that all classes call) and let computers do the work. It would also be interesting to know.Arched
Understood. In that case, as dumb as it sounds, what about replacing System.out.println() with System.out.println();Logger.log() to make sure that both the console gets the message and your class is notified?Africanist
Sigh, I wanted to avoid that since I have to do the same for debug and error. I guess that could work, and I could use a Regex with capturing groups so that log() has the same string as println().Arched
I am, fortunately, at a point in my career where I can tell managers what I think of their ridiculous constraints, and do it the Right Way if they don't have good reasons.Mims
P
2

This is just a nice singleton wrapper around Louis Wasserman's excellent answer. My code is free to use by anyone who wishes to use it. Using it you can get the console output anywhere in a fairly simple way.

public class SystemOutListener {

    private static SystemOutListener singleton;

    public static SystemOutListener GetSingleton() {
        if (singleton == null) {
            singleton = new SystemOutListener();
            singleton.ReplaceStandartSystemOutPrintStream();
        }
        return singleton;
    }
    private ArrayList<ISystemOutObserver> observersList = new ArrayList<>();

    public void AttachSystemOutObserver(ISystemOutObserver observer) {
        observersList.add(observer);
    }

    public void RemoveSystemOutObserver(ISystemOutObserver observer) {
        observersList.remove(observer);
    }

    private void FireSystemOutPrintln(String message) {
        for (int i = 0; i < observersList.size(); i++) {
            java.awt.EventQueue.invokeLater(new HandleSystemOutRunner(observersList.get(i), message));
        }
    }

    private void ReplaceStandartSystemOutPrintStream() {
        System.setOut(new PrintStream(System.out) {
            @Override
            public void println(String s) {
                super.println(s);
                FireSystemOutPrintln(s);
            }
        });
    }

    public interface ISystemOutObserver {
        public void HandleSystemOut(String message);
    }

    private class HandleSystemOutRunner implements Runnable {

        private String message;
        private ISystemOutObserver target;

        public HandleSystemOutRunner(ISystemOutObserver target, String message) {
            this.message = message;
            this.target = target;
        }

        @Override
        public void run() {
            target.HandleSystemOut(message);
        }
    }
}

Usage:

SystemOutListener.GetSingleton().AttachSystemOutObserver(/*YOUR OBSERVER*/)

Lambdas(Java 8) can be used in place of the observer, too!

Paugh answered 29/5, 2013 at 8:41 Comment(0)
R
1

Probably a thousand miles from what you need, but you could use something like "watch" under linux looking for specific text. If you were to log out to a file you could set "watch" to monitor the file for certain texts and issue instructions accordingly.

Rateable answered 9/2, 2012 at 21:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.