I am using Java 6. I have created a custom formatter which creates only the time and the message, but it always prints null class name and method name and the log level besides the time and the message in two lines:
Mar 8, 2015 6:48:09 PM null null
ALL: This is a message
Also, the log files generated are in the following format, where I expected it to start with xxx.log.0 first, once it is full, then xxx.log.1, but it generated all 10 files at the same time.
xxxx.log.0.9
xxxx.log.0.8
xxxx.log.0.7
xxxx.log.0.6
xxxx.log.0.5
xxxx.log.0.4
xxxx.log.0.3
Can someone let me know how I can log only the time and the message and how I correct the log file extensions? Much appreciated!
public class MyFormatter extends Formatter {
public String format(LogRecord record)
{
String recordStr = new Date() + " " + formatMessage(record)
return recordStr;
}
}
The code which uses MyFormatter:
Logger fileLogger = Logger.getLogger(xxxx.class.getPackage().getName());
FileHandler handler = new FileHandler(pattern, limit, numLogFiles, true);
MyFormatter formatter = new MyFormatter();
handler.setFormatter(formatter);
fileLogger.addHandler(handler);
Level logLevel = java.util.logging.Level.ALL;
fileLogger.log(new LogRecord(logLevel, "This is a message"));
I am using Java 6. I have created a custom formatter which creates only the time and the message, but it always prints null class name and method name and the log level besides the time and the message in two lines:
That output is from the java.util.logging.SimpleFormatter which has support for printing just the date and message. The following pattern can be used to change the SimpleFormatter to work like your custom formatter:
-Djava.util.logging.SimpleFormatter.format="[%1$tc] %5$s%n"
The code that uses your formatter is not setting the method name, class name, or logger name. Calling the Logger.log(Level,String) method will compute the call site for you.
private static final Logger fileLogger = Logger.getLogger(xxxx.class.getPackage().getName());
private static void initLogging() throws IOException {
FileHandler handler = new FileHandler(pattern, limit, numLogFiles, true);
MyFormatter formatter = new MyFormatter();
handler.setFormatter(formatter);
fileLogger.addHandler(handler);
fileLogger.log(Level.ALL, "This is a message");
}
Not sure if it is intended but, you should use the event time of the LogRecord and not the current time.
Also, the log files generated are in the following format, where I expected it to start with xxx.log.0 first, once it is full, then xxx.log.1, but it generated all 10 files at the same time.
For every FileHandler you create, you have to be sure it is closed by your code before you create a new one with the same pattern. By default the LogManager will close any attached handlers on shutdown. You also have to make sure that you hold a strong reference to the logger that holds the attached handler. Method local references like what is used in your example doesn't count.
Related
I have an issue on adding timestamp suffixes to files using spring integration.
Here is my FileWritingMessageHandler bean :
public FileWritingMessageHandler getFileWritingMessageHandler(String directory) {
FileWritingMessageHandler handler = new FileWritingMessageHandler(new File(directory));
handler.setFileExistsMode(FileExistsMode.REPLACE);
handler.setExpectReply(false);
handler.setDeleteSourceFiles(true);
return handler;
}
I tried with handler.setTemporaryFileSuffix(getCurrentTimeStamp()); but it does nothing
I tried also with a DefaultFileNameGenerator :
DefaultFileNameGenerator suffixFileNameGenerator = new DefaultFileNameGenerator();
suffixFileNameGenerator.setHeaderName("id");
suffixFileNameGenerator.setExpression("payload.name + '"+ getCurrentTimeStamp()+"'");
handler.setFileNameGenerator(suffixFileNameGenerator);
A timestamp is added but it's the same for all files. They are processed at different times so I would like to append that time to the file name.
How can I achieve that ?
Thanks in advance for your help
You are getting the time once and adding it as a literal to the expression.
You need to get the timestamp at runtime instead of bean initialization time; use the T operator to invoke a static method:
suffixFileNameGenerator.setExpression("payload.name + T(System).currentTimeMillis()");
Having some issues with a Mockito test.
I currently get this error:
Argument(s) are different! Wanted:
repository.save(
uk.co.withersoft.docservice.repositories.hibernate.MetaDataEntity#3e437e6c
);
-> at uk.co.withersoft.docservice.datastore.impl.MetaDataStoreImplTest.storeClaimMetadata(MetaDataStoreImplTest.java:55)
Actual invocation has different arguments:
repository.save(
uk.co.withersoft.docservice.repositories.hibernate.MetaDataEntity#3e361ee2
);
I'm pretty sure its because the times within MetaDataEntity are different
//This is what I should be getting
id = null
metaData = "{"caseReference":"CN00000001","claimReference":"LN00000001","rpsDocumentType":"REJ","documentTitle":"Claims LN00000001 (Claimant: Mr LOCAL HOST) REJ-Rejection letter"}"
batchId = 0
state = "Saved MetaData to DB"
lastUpdatedDate = {Timestamp#1517} "2018-07-25 18:39:21.993"
createdDate = {Timestamp#1518} "2018-07-25 18:39:21.993"
// This is actually what I get.
id = null
metaData = "{"caseReference":"CN00000001","claimReference":"LN00000001","rpsDocumentType":"REJ","documentTitle":"Claims LN00000001 (Claimant: Mr LOCAL HOST) REJ-Rejection letter"}"
batchId = 0
state = "Saved MetaData to DB"
lastUpdatedDate = {Timestamp#1530} "2018-07-25 18:39:49.274"
createdDate = {Timestamp#1531} "2018-07-25 18:39:52.716"
Here is my test case:
#Test
public void storeClaimMetadata () throws JsonProcessingException {
ClaimMetaData metaData = constructMetaData();
MetaDataEntity mockResponseMetaDataEntity = new MetaDataEntity();
mockResponseMetaDataEntity.setId(1);
when(repository.save(any(MetaDataEntity.class))).thenReturn(mockResponseMetaDataEntity);
Integer result = testSubject.storeClaimMetadata(metaData);
assertEquals(Integer.valueOf(1), result);
final ObjectMapper mapper = new ObjectMapper();
String jsonMetaData = mapper.writeValueAsString(metaData);
MetaDataEntity expectedMetaDataEntity = new MetaDataEntity(null,
jsonMetaData,
0,
"Saved MetaData to DB",
new Timestamp(System.currentTimeMillis()),
new Timestamp(System.currentTimeMillis()));
Mockito.verify(repository, times(1)).save(expectedMetaDataEntity);
}
//Creates a ClaimRequest
private ClaimMetaData constructMetaData() {
final ClaimMetaData metaData = new ClaimMetaData("CN00000001",
"LN00000001",
"REJ",
"Claims LN00000001 (Claimant: Mr LOCAL HOST) REJ-Rejection letter");
return metaData;
}
Any help would be much appreciated. This has been driving me crazy!!
This is exactly why people use dependency injection, so they can specify test collaborators that give back predictable results. Replace the hardcoded new Timestamp(System.currentTimeMillis) stuff with calls to Timestamp.from(Instant.now(clock)).
java.time.Clock is an interface that you can use to get your timestamp values. The real implementation can be injected into the code being tested, using one of the factory methods that returns a system clock, like this (using Spring Java configuration):
#Bean
public Clock clock() {
return Clock.systemDefaultZone();
}
and for the test code you can have an implementation where you specify the time you want the clock to return:
#Before
public void setUp() {
clock = Clock.fixed(date.toInstant(), ZoneId.of("America/NewYork"));
systemUnderTest.setClock(clock);
}
This is "works as designed".
You are invoking a service that computes timestamps. Like, now.
Then you have a test case that has some setup going on, and fetches time stamps, too. Now.
Guess what: albeit these two "nows above are close to each other, there is still a bit of delay between them.
You are checking for equality, can only work when the time stamps are identical! But they aren't, because they are created one after the other, with very well noticeable delays in between!
Meaning: you need to look how you could control which timestamps are created within your application, like saying "the timestamps should be t1 and t2". So that your test can then check "I found t1 and t2".
Alternatively, you simply change your verification step: instead of trying to have "equal" objects (that can't be equal because different time stamps!), you could compare those parts that should be equal, and for the time stamps, you could check that they are "close enough".
In Code , instead of using new Timestamp(System.currentTimeMillis()) , you can use
new Timestamp(DateTimeUtils.currentTimeMillis()). Here DateTimeUtils is from jodatime.
In test cases, can use below.
private SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss:SSS");
#Before
public void before() throws Exception {
// define a fixed date-time
Date fixedDateTime = DATE_FORMATTER.parse("01/07/2016 16:45:00:000");
DateTimeUtils.setCurrentMillisFixed(fixedDateTime.getTime());
}
#After
public void after() throws Exception {
// Make sure to cleanup afterwards
DateTimeUtils.setCurrentMillisSystem();
}````
is there any possibility to add timestamp to every line which is printed in Eclipse console? For example when code like
System.out.println("Hello World");
is executed I would like to have something like this in console:
[yy-mm-dd hh-mm-ss] Hello World
Thank you in advance for any sugestions.
I am not sure if third party library straightaway provides it. But you can create custom print method to achieve it and use it across the project
public void customPrint(String inputToPrint){
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date now = new Date();
String strDate = sdfDate.format(now);
System.out.println("[" + strDate + "] " + inputToPrint);
}
This kind of goal is usually satisfied automatically by logging libraries like Logback. With a logging library you would instantiate a logger at the class level
private static final Logger LOG = LoggerFactory.getLogger(MyClass.class);
and then write your log messages through the logger:
LOG.debug("Here's my log message")
The output format is configurable, but one example of output is this:
2013-12-14 11:21:05.985 ["http-bio-8080"-exec-5] DEBUG c.s.m.i.MyClass - Here's my log message
Need a quick help. I am a newbie in QuickFixJ. I have a FIX message in a txt file. I need to convert that into FIX50SP2 format. I am enclosing the code snippet.
String fixMsg = "1128=99=25535=X49=CME34=47134052=20100318-03:21:11.36475=20120904268=2279=122=848=336683=607400107=ESU2269=1270=140575271=152273=121014000336=2346=521023=1279=122=848=336683=607401107=ESU2269=1270=140600271=206273=121014000336=2346=681023=210=159";
System.out.println("FixMsg String:"+fixMsg);
Message FIXMessage = new Message();
DataDictionary dd = new DataDictionary("FIX50SP2.xml");
FIXMessage.fromString(fixMsg, dd, false);
System.out.println("FIXMessage Output:" + FIXMessage.toString()); // Print message after parsing
MsgType msgType = new MsgType();
System.out.println(FIXMessage.getField(msgType));
Here is the output:
FixMsg String:1128=99=15835=X49=CME34=47164052=2012090312102051175=20120904268=1279=122=848=336683=607745107=ESU2269=1270=140575271=123273=121020000336=2346=501023=110=205
FIXMessage Output:9=6135=X34=47164049=CME52=2012090312102051175=20120904268=110=117
quickfix.FieldNotFound: Field [35] was not found in message.
at quickfix.FieldMap.getField(FieldMap.java:216)
at quickfix.FieldMap.getFieldInternal(FieldMap.java:353)
at quickfix.FieldMap.getField(FieldMap.java:349)
at MainApp.main(MainApp.java:52)
I want to extract MsgType field (field 35). Could you please tell me where I am wrong? The thing I have observed is that after parsing to FIX50SP2 format, the convert FIX message is missing many data element (for details see the output)
Thanks
Like others mentioned the MsgType is an header field and you get it by using the following
String msgType = null;
if(FIXMessage.getHeader().isSetField(MsgType.FIELD)) {
msgType = FIXMessage.getHeader().getString(MsgType.FIELD);
}
System.out.println("MsgType is " + msgType);`
The reason you are missing many data element after parsing is, probably your message have some custom tags(like tag 2346), which is not defined in your data dictionary(FIXSP02.xml). hence the parsing of those tags failed and missing in the output.
To fix this, get the data dictionary from the party that is sending you the message and use it to parse the message
I'm not familiar with FIX messages and QuickFixJ, but glancing at the Javadoc, it seems like you should use the identifyType method :
String fixMsg = "1128=99=25535=X49=CME34=47134052=20100318-03:21:11.36475=20120904268=2279=122=848=336683=607400107=ESU2269=1270=140575271=152273=121014000336=2346=521023=1279=122=848=336683=607401107=ESU2269=1270=140600271=206273=121014000336=2346=681023=210=159";
MsgType msgType = Message.identifyType(fixMsg);
You may find FixB framework useful as it deals well with non-standard use cases of FIX.
As in your case, to extract only data you are interested in, you need to define a class that will represent this data and to bind it to FIX using annotations. E.g.:
#FixBlock
public class MDEntry {
#FixField(tag=269) public int entryType; // you could define an enum type for it as well
#FixField(tag=278) public String entryId;
#FixField(tag=55) public String symbol;
}
...
FixFieldExtractor fixExtractor = new NativeFixFieldExtractor();
List<MDEntry> mdEntries = fixExtractor.getGroups(fixMsg, List.class, 268, FixMetaScanner.scanClass(MDEntry.class))
In more common cases, FixSerializer interface should be used, but it requires a message with MsgType(35) tag and a class annotated with #FixMessage(type="...") accordingly. E.g.:
#FixMessage(type="X")
public class MarketData {
#FixGroup(tag=268) public List<MDEntry> entries;
}
...
FixMetaDictionary fixMetaDictionary = FixMetaScanner.scanClassesIn("my.fix.classes.package");
FixSerializer fixSerializer = new NativeFixSerializer("FIX.5.0.SP2", fixMetaDictionary);
MarketData marketData = fixSerializer.deserialize(fixMsg);
I hope you will find it useful.
If you need just a MsgTyp, you're sure the message is correct and you do not need any other field from the message, then I would recommend extracting MsgType from string using regexp.
e.g.: \u000135=(\w+)\u0001
It is MUCH FASTER than parsing (and validating) a string via QuickFix.
At the moment a default entry looks something like this:
Oct 12, 2008 9:45:18 AM myClassInfoHere
INFO: MyLogMessageHere
How do I get it to do this?
Oct 12, 2008 9:45:18 AM myClassInfoHere - INFO: MyLogMessageHere
Clarification I'm using java.util.logging
As of Java 7, java.util.logging.SimpleFormatter supports getting its format from a system property, so adding something like this to the JVM command line will cause it to print on one line:
-Djava.util.logging.SimpleFormatter.format='%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n'
Alternatively, you can also add this to your logger.properties:
java.util.logging.SimpleFormatter.format='%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n'
Similar to Tervor, But I like to change the property on runtime.
Note that this need to be set before the first SimpleFormatter is created - as was written in the comments.
System.setProperty("java.util.logging.SimpleFormatter.format",
"%1$tF %1$tT %4$s %2$s %5$s%6$s%n");
1) -Djava.util.logging.SimpleFormatter.format
Java 7 supports a property with the java.util.Formatter format string syntax.
-Djava.util.logging.SimpleFormatter.format=...
See here.
My favorite is:
-Djava.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$-6s %2$s %5$s%6$s%n
which makes output like:
2014-09-02 16:44:57 SEVERE org.jboss.windup.util.ZipUtil unzip: Failed to load: foo.zip
2) Putting it to IDEs
IDEs typically let you set system properties for a project.
E.g. in NetBeans, instead of adding -D...=... somewhere, add the property in the action dialog, in a form of java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-... - without any quotes. The IDE should figure out.
3) Putting that to Maven - Surefire
For your convenience, Here is how to put it to Surefire:
<!-- Surefire -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<systemPropertyVariables>
<!-- Set JUL Formatting -->
<java.util.logging.SimpleFormatter.format>%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$-6s %2$s %5$s%6$s%n</java.util.logging.SimpleFormatter.format>
</systemPropertyVariables>
</configuration>
</plugin>
4) Hand-made
I have a library with few java.util.logging related classes. Amongst them, it's SingleLineFormatter.
Downloadable jar here.
public class SingleLineFormatter extends Formatter {
Date dat = new Date();
private final static String format = "{0,date} {0,time}";
private MessageFormat formatter;
private Object args[] = new Object[1];
// Line separator string. This is the value of the line.separator
// property at the moment that the SimpleFormatter was created.
//private String lineSeparator = (String) java.security.AccessController.doPrivileged(
// new sun.security.action.GetPropertyAction("line.separator"));
private String lineSeparator = "\n";
/**
* Format the given LogRecord.
* #param record the log record to be formatted.
* #return a formatted log record
*/
public synchronized String format(LogRecord record) {
StringBuilder sb = new StringBuilder();
// Minimize memory allocations here.
dat.setTime(record.getMillis());
args[0] = dat;
// Date and time
StringBuffer text = new StringBuffer();
if (formatter == null) {
formatter = new MessageFormat(format);
}
formatter.format(args, text, null);
sb.append(text);
sb.append(" ");
// Class name
if (record.getSourceClassName() != null) {
sb.append(record.getSourceClassName());
} else {
sb.append(record.getLoggerName());
}
// Method name
if (record.getSourceMethodName() != null) {
sb.append(" ");
sb.append(record.getSourceMethodName());
}
sb.append(" - "); // lineSeparator
String message = formatMessage(record);
// Level
sb.append(record.getLevel().getLocalizedName());
sb.append(": ");
// Indent - the more serious, the more indented.
//sb.append( String.format("% ""s") );
int iOffset = (1000 - record.getLevel().intValue()) / 100;
for( int i = 0; i < iOffset; i++ ){
sb.append(" ");
}
sb.append(message);
sb.append(lineSeparator);
if (record.getThrown() != null) {
try {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
record.getThrown().printStackTrace(pw);
pw.close();
sb.append(sw.toString());
} catch (Exception ex) {
}
}
return sb.toString();
}
}
Like Obediah Stane said, it's necessary to create your own format method. But I would change a few things:
Create a subclass directly derived from Formatter, not from SimpleFormatter. The SimpleFormatter has nothing to add anymore.
Be careful with creating a new Date object! You should make sure to represent the date of the LogRecord. When creating a new Date with the default constructor, it will represent the date and time the Formatter processes the LogRecord, not the date that the LogRecord was created.
The following class can be used as formatter in a Handler, which in turn can be added to the Logger. Note that it ignores all class and method information available in the LogRecord.
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
public final class LogFormatter extends Formatter {
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
#Override
public String format(LogRecord record) {
StringBuilder sb = new StringBuilder();
sb.append(new Date(record.getMillis()))
.append(" ")
.append(record.getLevel().getLocalizedName())
.append(": ")
.append(formatMessage(record))
.append(LINE_SEPARATOR);
if (record.getThrown() != null) {
try {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
record.getThrown().printStackTrace(pw);
pw.close();
sb.append(sw.toString());
} catch (Exception ex) {
// ignore
}
}
return sb.toString();
}
}
This is what I'm using.
public class VerySimpleFormatter extends Formatter {
private static final String PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
#Override
public String format(final LogRecord record) {
return String.format(
"%1$s %2$-7s %3$s\n",
new SimpleDateFormat(PATTERN).format(
new Date(record.getMillis())),
record.getLevel().getName(), formatMessage(record));
}
}
You'll get something like...
2016-08-19T17:43:14.295+09:00 INFO Hey~
2016-08-19T17:43:16.068+09:00 SEVERE Seriously?
2016-08-19T17:43:16.068+09:00 WARNING I'm warning you!!!
Per screenshot, in Eclipse select "run as" then "Run Configurations..." and add the answer from Trevor Robinson with double quotes instead of quotes. If you miss the double quotes you'll get "could not find or load main class" errors.
I've figured out a way that works. You can subclass SimpleFormatter and override the format method
public String format(LogRecord record) {
return new java.util.Date() + " " + record.getLevel() + " " + record.getMessage() + "\r\n";
}
A bit surprised at this API I would have thought that more functionality/flexibility would have been provided out of the box
If you log in a web application using tomcat add:
-Djava.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
On VM arguments
This logging is specific to your application and not a general Java feature. What application(s) are you running?
It might be that this is coming from a specific logging library that you are using within your own code. If so, please post the details of which one you are using.
if you're using java.util.logging, then there is a configuration file that is doing this to log contents (unless you're using programmatic configuration). So, your options are
1) run post -processor that removes the line breaks
2) change the log configuration AND remove the line breaks from it. Restart your application (server) and you should be good.