Loading... |
Reply to author |
Edit post |
Move post |
Delete this post |
Delete this post and replies |
Change post date |
Print post |
Permalink |
Raw mail |
Hi guys, I am trying to redirect the messages sent by Asciidoctor (Ruby) in console to AsciidoctorJ logging system. I have found some examples in the internet and I don't know why but it doesn't work. I have created a test class to isolate the problem:
public class Main { static Logger logger; static { logger = Logger.getLogger("xxx"); FileHandler fh; try { fh = new FileHandler("./MyLogFile.log"); logger.addHandler(fh); SimpleFormatter formatter = new SimpleFormatter(); fh.setFormatter(formatter); } catch (SecurityException | IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.setOut(new PrintStream(new LoggingOutputStream(logger, Level.INFO))); System.setErr(new PrintStream(new LoggingOutputStream(logger))); } public static void main(String args[]) { System.out.println("Hello"); } static class LoggingOutputStream extends ByteArrayOutputStream { private String lineSeparator; private Logger logger; private Level level; public LoggingOutputStream(Logger logger) { super(); this.logger = logger; this.lineSeparator = System.getProperty("line.separator"); } public LoggingOutputStream(Logger logger, Level level) { super(); this.logger = logger; this.level = level; this.lineSeparator = System.getProperty("line.separator"); } public void flush() throws IOException { String record; synchronized(this) { super.flush(); record = this.toString(); super.reset(); if (record.length() == 0 || record.equals(this.lineSeparator)) { // avoid empty records return; } System.out.println("My Log: "+record); if(this.logger == null) { if(record.contains("WARNING")) { this.logger.logp(Level.WARNING, "Asciidoctor", "", record); } else { if(record.contains("FAILED")) { this.logger.logp(Level.SEVERE, "Asciidoctor", "", record); } else { this.logger.logp(Level.INFO, "Asciidoctor", "", record); } } } else { this.logger.logp(this.level, "", "", record); } } } } } I don't know why but flush method is never called (I thought that this method will be called by Logger) but it seems not. Any idea on how to implement this? |
Loading... |
Reply to author |
Edit post |
Move post |
Delete this post |
Delete this post and replies |
Change post date |
Print post |
Permalink |
Raw mail |
Hi,
I'm not sure if this is the right approach but I found some things that explain why this may fail. First, the `PrintStream` constructor used sets the attribute `autofush` to false, setting this to true using: System.setOut(new PrintStream(new LoggingOutputStream(logger, Level.INFO), true)); ensures that flush is invoked. This helps testing, but I think that a previous error is preventing the method from ever being called. Secondly, and i think the real problem is that the test to crush because some recursive loops, so far I've seen that calling logger.log inside the flush method triggers to call it again-and-again until it crashes. Also, a minor detail the logger can have a null level, making the last line crash sometimes. Seems like playing with the logger is trickier than it seems :% |
Loading... |
Reply to author |
Edit post |
Move post |
Delete this post |
Delete this post and replies |
Change post date |
Print post |
Permalink |
Raw mail |
I have managed to run it correctly with the help of Romain. Note that what it misses is the \n:
public class Run { static Logger logger; static { logger = Logger.getLogger("Asciidoctor"); LoggerOutputStream out = new LoggerOutputStream(logger); System.setOut(new PrintStream(out)); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { try { // can log or not something depending logger is already closed or not, best is to call it manually at the end of main if possible out.flush(); } catch (final IOException e) { // no-op } } }); } public static void main(String[] args) { // final PrintStream original = System.out; // if both redirections are needed doWork(); } private static void doWork() { System.out.println("test1"); System.out.print("test2"); } static class LoggerOutputStream extends OutputStream { private final StringBuilder builder = new StringBuilder(); private Logger logger; public LoggerOutputStream(Logger logger) { this.logger = logger; } private boolean doLog() { synchronized(this) { if (builder.length() > 0) { logger.info(builder.toString()); builder.setLength(0); return true; } return false; } } @Override public void write(int b) throws IOException { if (b == '\n') { if (!doLog()) { logger.info(""); } } else { builder.append((char) b); } } @Override public void flush() throws IOException { doLog(); } @Override public void close() throws IOException { doLog(); } }; } |
Loading... |
Reply to author |
Edit post |
Move post |
Delete this post |
Delete this post and replies |
Change post date |
Print post |
Permalink |
Raw mail |
Administrator
|
Alex, Your approach is certainly a sound one, though it does point to how important it is to have a proper logging hook in Asciidoctor because we really don't want to have to do this long term. Then again, we kind of already know that it's an important thing to fix, but seeing this code removes all doubt in my mind of the importance. I do want to document the other approach I had briefly suggested over Twitter. Instead of intercepting System.out and System.err across the whole JVM, you could isolate this to the Ruby environment by reassigning the $stdout and $stderr global variables in the JRuby runtime when you set it up. That way, you'll only trap the $stdout and $stderr channels that Ruby uses (mostly like the Asciidoctor gem). You'd implement this by creating an adapter for the Logger that responds to the "puts" method and passes it to the Logger. ...but even reading what I just wrote makes it clear how insane it is that we don't have a logger interface in Asciidoctor that you can implement {1}. I'm going to schedule this change for 1.5.3 and see if we can get it done by then. Cheers, -Dan On Fri, Dec 12, 2014 at 8:25 AM, asotobu [via Asciidoctor :: Discussion] <[hidden email]> wrote: I have managed to run it correctly with the help of Romain. Note that what it misses is the \n: ... [show rest of quote] Dan Allen | http://google.com/profiles/dan.j.allen |
Free forum by Nabble | Edit this page |