12

Someone has a code example of how log4j can be used to create logs in Mathematica?

RLink uses it, as can be checked in initLogger[] function, in this file:

SystemOpen@FileNameJoin@{DirectoryName@DirectoryName@FindFile["RLink`"], "RLink.m"}

But it's not a stand alone code. If someone has a simpler one, I would appreciate.

Murta
  • 26,275
  • 6
  • 76
  • 166
  • 1
    One username comes to my mind :) – Dr. belisarius Oct 04 '15 at 00:17
  • @belisarius yes... some friend, that as you, has more than 70k points. – Murta Oct 04 '15 at 00:22
  • Well, the code in RLink pretty much shows how this can be used. The only missing piece is the logger instance, which is referred there as RLinkInit`rlogger, and for which instead you can use Logger`getLogger["YourApp"]. And you will have to first LoadJavaClass["org.apache.log4j.Logger"], and add the log4j.jar to the classpath. – Leonid Shifrin Oct 04 '15 at 00:24
  • @LeonidShifrin, interesting. Now I'm a little more comfortable with Java and Mathematica. I'll make some tests. tks – Murta Oct 04 '15 at 00:30
  • I will post a minimal code, in a moment. – Leonid Shifrin Oct 04 '15 at 00:39

1 Answers1

8

Minimal code

Here is a minimal code (partly adopted from RLink), to get you started. First, load JLink:

Needs["JLink`"]
InstallJava[]

Here is the code:

ClearAll[logIt];
logIt[logger_,msg_String,mode_String]:=
  Block[{trace, debug, info, warn, error, fatal},
    With[{
      method = mode /. {
        "TRACE" -> trace, 
        "DEBUG" -> debug, 
        "INFO" -> info, 
        "WARN" -> warn, 
        "FATAL" -> fatal,
        _ :> Return[$Failed, Block]
      }},
      JavaBlock@logger@method[JavaNew["java.lang.String", msg]]
    ]
  ];

logIt[logger_,msg_String]:=logIt[logger, msg, "INFO"];

And the initLogger function:

ClearAll[initLogger];
initLogger[logger_, logFile_]:=
  Module[{},        
    logger@removeAllAppenders[];
    logger@addAppender[
      JavaNew["org.apache.log4j.ConsoleAppender"]
    ];
    logger@addAppender[
      JavaNew[
        "org.apache.log4j.FileAppender", 
        JavaNew["org.apache.log4j.SimpleLayout"],           
        logFile
      ]
    ];
    logIt[logger, "Logger initialized"];
  ];    

Example of use

Here is an example (I assume that log4j is already on the classpath, which is usually so, because it is used also internally in Mathematica):

LoadJavaClass["org.apache.log4j.Logger"]

Now create a logger instance:

logger = Logger`getLogger["MyApp"]

(* « JavaObject[org.apache.log4j.Logger]» *)

and the log file:

$logFile = FileNameJoin[{$TemporaryDirectory, "mylog.txt"}];

Now, initialize the logger:

initLogger[logger, $logFile]

You can test:

Import[$logFile, "String"]

(* "INFO - Logger initialized" *)

Now log something:

Do[
  If[i < 5, 
    logIt[logger, "i = " <> ToString [i]], 
    logIt[logger, "fatal error", "FATAL"]; Break[]
  ], 
  {i, 1, 10}
]

check:

Import[$logFile, "String"]

"INFO - Logger initialized
 INFO - i = 1
 INFO - i = 2
 INFO - i = 3
 INFO - i = 4
 FATAL - fatal error"

You can do more interesting things with loggers with log4j, but this example should get you started.

Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
  • Tks a lot! Works like a charm! +1 – Murta Oct 04 '15 at 01:07
  • @Murta Glad to help, as usual. Thanks for the accept! – Leonid Shifrin Oct 04 '15 at 13:11
  • 1
    @Murta Of course, the real reason why I used log4j in RLink is that I could append to the logger on both Mathematica and Java sides of RLink. If you only need Mathematica - side, you can simply use appending to a file. But for the hybrid Java / Mathematica apps, being able to use one and the same logger for both sides is important. The way you do this is to have a logger be a field of some Java class on the Java side, and then pass that instance to Mathematica. For RLink, the logger is a (static) field of RLinkInit class , accessed via RLinkInit`rlogger in Mathematica. – Leonid Shifrin Oct 04 '15 at 15:07