How to log repeated warnings only once - java

There is a pattern that happens every now and then. I have a method called many times, and it contains this snippet:
Foo foo = getConfiguredFoo();
if (foo == null) {
logger.warn("Foo not configured");
foo = getDefaultFoo();
}
Then my log file is cluttered with this warning a hundred times. I know I can grep it out, but I wonder if there is a better way to see this warning only once.
Note: the duplication of messages is a correct behavior by default, so this is not about avoiding unintentional duplicate log message. I tagged my question as log4j, but I'm open to other java logging frameworks.

Here is what I can come up with: a class that accumulates warnings which can be dumped at the end. It's in groovy, but you can get the point. The dumping part can be customized to use a logger, of course.
class BadNews {
static Map<String,List<Object>> warnings = [:];
static void warn(String key, Object uniqueStuff) {
def knownWarnings = warnings[key]
if (! knownWarnings) {
knownWarnings = []
warnings[key] = knownWarnings
}
knownWarnings << uniqueStuff
}
static void dumpWarnings(PrintStream out) {
warnings.each{key, stuffs ->
out.println("$key: " + stuffs.size())
stuffs.each{
out.println("\t$it")
}
}
}
}
class SomewhereElse {
def foo(Bar bar) {
if (! bar)
BadNews.warn("Empty bar", this)
}
}

I faced a similar problem sometime ago but could not find any way of dealing with this in Log4J.
I finally did the following:
Foo foo = getConfiguredFoo();
if (foo == null) {
if(!warningLogged)logger.warn("Foo not configured");
warningLogged = true
foo = getDefaultFoo();
}
This solution is OK if you have one or two log statements you don't want to see repeated in your logs but does not scale up with more log statements (you need a boolean for every message logged)

You could write a wrapper around your logging to store the last line logged. Depending on how you implement, you could add some sort of counter to log how many times it got logged or you may choose to subclass Logger instead of having an external wrapper. Could be configurable with a boolean suppressDuplicates if you needed that too.
public class LogWrapper{
Logger logger = Logger.getLogger("your logger here");
String lastLine = new String();
public void warn(String s){
if (lastLine.compareToIgnoreCase(s) == 0)
return;
else {
lastLine = s;
logger.warn(s);
}
}
}

If this is the only thing you want to print one time, then using a saved boolean would be your best bet. If you wanted something you could use throughout your project, I have created something that may be useful. I just created a Java class that uses a log4j logger instance. When I want to log a message, I just do something like this:
LogConsolidated.log(logger, Level.WARN, 5000, "File: " + f + " not found.", e);
Instead of:
logger.warn("File: " + f + " not found.", e);
Which makes it log a maximum of 1 time every 5 seconds, and prints how many times it should have logged (e.g. |x53|). Obviously, you can make it so you don't have as many parameters, or pull the level out by doing log.warn or something, but this works for my use case.
For you (if you only want to print one time, every time) this is overkill, but you can still do it by passing in something like: Long.MAX_LONG in as the 3rd parameter. I like the flexibility to be able to determine frequency for each specific log message (hence the parameter). For example, this would accomplish what you want:
LogConsolidated.log(logger, Level.WARN, Long.MAX_LONG, "File: " + f + " not found.", e);
Here is the LogConsolidated class:
import java.util.HashMap;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
public class LogConsolidated {
private static HashMap<String, TimeAndCount> lastLoggedTime = new HashMap<>();
/**
* Logs given <code>message</code> to given <code>logger</code> as long as:
* <ul>
* <li>A message (from same class and line number) has not already been logged within the past <code>timeBetweenLogs</code>.</li>
* <li>The given <code>level</code> is active for given <code>logger</code>.</li>
* </ul>
* Note: If messages are skipped, they are counted. When <code>timeBetweenLogs</code> has passed, and a repeat message is logged,
* the count will be displayed.
* #param logger Where to log.
* #param level Level to log.
* #param timeBetweenLogs Milliseconds to wait between similar log messages.
* #param message The actual message to log.
* #param t Can be null. Will log stack trace if not null.
*/
public static void log(Logger logger, Level level, long timeBetweenLogs, String message, Throwable t) {
if (logger.isEnabledFor(level)) {
String uniqueIdentifier = getFileAndLine();
TimeAndCount lastTimeAndCount = lastLoggedTime.get(uniqueIdentifier);
if (lastTimeAndCount != null) {
synchronized (lastTimeAndCount) {
long now = System.currentTimeMillis();
if (now - lastTimeAndCount.time < timeBetweenLogs) {
lastTimeAndCount.count++;
return;
} else {
log(logger, level, "|x" + lastTimeAndCount.count + "| " + message, t);
}
}
} else {
log(logger, level, message, t);
}
lastLoggedTime.put(uniqueIdentifier, new TimeAndCount());
}
}
private static String getFileAndLine() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
boolean enteredLogConsolidated = false;
for (StackTraceElement ste : stackTrace) {
if (ste.getClassName().equals(LogConsolidated.class.getName())) {
enteredLogConsolidated = true;
} else if (enteredLogConsolidated) {
// We have now file/line before entering LogConsolidated.
return ste.getFileName() + ":" + ste.getLineNumber();
}
}
return "?";
}
private static void log(Logger logger, Level level, String message, Throwable t) {
if (t == null) {
logger.log(level, message);
} else {
logger.log(level, message, t);
}
}
private static class TimeAndCount {
long time;
int count;
TimeAndCount() {
this.time = System.currentTimeMillis();
this.count = 0;
}
}
}

Related

How to report and integrate Extent or Junit report to "For loop" test scenarios and add assertion report Pass and Fail

I am automating e-commerce website. I am using JUNIT-Selenium framework.
Their are two files i am working with, first is the "TestCase.java" where my test steps are mentioned, aslo to start automation i run this file and second file is "TestMain.java" which has validation methods which will used by First file to verify and input the data in UI (mostly using If ..else validation).
First file consist of Automation initiation code, which uses Hashmap for reading the excel, extent report initiation and flush and use methods from testMain.java for input of data and validation through if... else statement.
TestCase.java looks like this:
public class TestCase extends AppTest {
private StringBuffer verificationErrors = new StringBuffer();
#Override
#Before
public void setUp() throws Exception {
super.setUp();
preparation = new Prep();
application = new AppToTest();
user = new Environment();
}
#Test
public void testLAP_Creamix() throws Exception {
try {
launchMainApplication();
Test_frMain Test_frMainPage = new Test_frMain(tool, test, user, application);
HashMap<String, ArrayList<String>> win = CreamixWindowsDataset.main();
SortedSet<String> keys = new TreeSet<>(win.keySet());
ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter("Test_Report.html");
ExtentReports extent = new ExtentReports();
extent.attachReporter(htmlReporter);
ExtentTest test1 = extent.createTest("Creamix test");
for (String i : keys) {
System.out.println("########### Test = " + win.get(i).get(0) + " ###########");
Lapeyre_frMainPage.EnterTaille(win.get(i).get(1));
Lapeyre_frMainPage.SelectCONFIGURATION(win.get(i).get(2));
Lapeyre_frMainPage.SelectPLANVASQUE(win.get(i).get(3));
Lapeyre_frMainPage.SelectCOULEUR(win.get(i).get(4));
Lapeyre_frMainPage.SelectPOIGNEES(win.get(i).get(5));
Lapeyre_frMainPage.SelectTYPE_DE_MEUBLE(win.get(i).get(6));
Lapeyre_frMainPage.SelectCHOISISSEZ(win.get(i).get(7));
Lapeyre_frMainPage.VerifyREFERENCE(win.get(i).get(8));(FROM HERE Validation Starts)
Lapeyre_frMainPage.VerifyQUANTITY(win.get(i).get(9));
Lapeyre_frMainPage.VerifyREFERENCETwo(win.get(i).get(10));
Lapeyre_frMainPage.VerifyQUANTITYTwo(win.get(i).get(11));
Lapeyre_frMainPage.VerifyREFERENCEThree(win.get(i).get(12));
Lapeyre_frMainPage.VerifyQUANTITYThree(win.get(i).get(13));
Lapeyre_frMainPage.VerifyREFERENCEFour(win.get(i).get(14));
Lapeyre_frMainPage.VerifyQUANTITYFour(win.get(i).get(15));
Lapeyre_frMainPage.VerifyREFERENCEFive(win.get(i).get(16));
Lapeyre_frMainPage.VerifyQUANTITYFive(win.get(i).get(17));
Lapeyre_frMainPage.VerifyREFERENCESix(win.get(i).get(18));
Lapeyre_frMainPage.VerifyQUANTITYSix(win.get(i).get(19));
Lapeyre_frMainPage.VerifyREFERENCESeven(win.get(i).get(20));
Lapeyre_frMainPage.VerifyQUANTITYSeven(win.get(i).get(21));
Lapeyre_frMainPage.VerifyPanierPrice(win.get(i).get(22));
Lapeyre_frMainPage.VerifyECO_PARTPrice(win.get(i).get(23));
Lapeyre_frMainPage.ClickCREAMIXReinit();(Reset button to test next scenario)
test1.pass("Scenario " + win.get(i).get(0) + " is passed");
System.out.println("########### Test End ##############");
extent.flush();----------(Extent report over)
}
test.setResult("pass");
} catch (AlreadyRunException e) {
} catch (Exception e) {
verificationErrors.append(e.getMessage());
throw e;
}
}
#Override
#After
public void tearDown() throws Exception {
super.tearDown();
}
}
(Please note one loop is one scenario where im customizing and validating price of the product and then clicking reset button to next scenario for doing same)
And,
"TestMain.java" from where i am using methods to validate
one of the method is shown below
public void VerifyREFERENCE(String REF_1) throws Exception {
System.out.println("Verifying reference article");
if (REF_1.equals("SKIP")) {
System.out.println("SKIPPED");
} else {
WebElement referenceOne = tool.searchUsingXPath("//tbody//tr[1]//td//div[2]");
String Ref1 = referenceOne.getText().trim();
System.out.println("ref 1 is " + Ref1);
if (Ref1.equals("Ref. de l'article : " + REF_1)) {
System.out.println("Reference 1 is correct");
} else {
System.out.println("Reference 1 is incorrect");
}
}
}
I am using extent report in TestCase.java(Please check above code) to report my scenarios, but the problem is It shows all test case as PASS and if any failure occurs it doesn't report(it terminates).
Reason being i have not used assertions anywhere, BUT HOW CAN I APPLY SUCH ASSERTIONS IN THIS FRAMEWORK
TO SUMMARIZE:
1- I need to add price validation check in report
2- i tried of using this line in TestCase.java "assertEquals("Verify REFERENCE 1", win.get(i).get(8), Lapeyre_frMainPage.GetREFERENCE());" but i cant use assertion in TestCase.java(it wont allow me).
3- Please show me alternative way to report PASS and FAIL for such frameworks, where in extent report i can able to show price mismatch between excel and UI.
You can only expect assertEquals() to work if your TestCase class extends junit test, or if you implement the method yourself in your code.
In any case, you seem to be trying to use ExtentReports. I am not experienced with that library, but according to the javadoc for ExtentTest, it appears that you are expected to call .pass() or .fail() yourself based on the outcome of your test.
In your TestCase, I believe you want to try to maintain a boolean to track if the test has passed or not.
The first step would be to modify VerifyREFERENCE() to return a boolean indicating if it passed or failed, instead of being void.
public boolean VerifyREFERENCE(String REF_1) throws Exception {
System.out.println("Verifying reference article");
if (REF_1.equals("SKIP")) {
System.out.println("SKIPPED");
} else {
WebElement referenceOne = tool.searchUsingXPath("//tbody//tr[1]//td//div[2]");
String Ref1 = referenceOne.getText().trim();
System.out.println("ref 1 is " + Ref1);
if (Ref1.equals("Ref. de l'article : " + REF_1)) {
System.out.println("Reference 1 is correct");
return true;
} else {
System.out.println("Reference 1 is incorrect");
return false;
}
}
}
Then, in your TestCase, initialise a boolean to true just before the loop. Inside the loop, perform a logical AND (&&) with the return value of each VerifyREFERENCE() call. Finally, after the loop finishes, test the value of the boolean, and pass or fail the ExtentTest as appropriate:
ExtentTest test1 = extent.createTest("Creamix test");
boolean passed = true;
for (String i : keys) {
System.out.println("########### Test = " + win.get(i).get(0) + " ###########");
Lapeyre_frMainPage.EnterTaille(win.get(i).get(1));
....
Lapeyre_frMainPage.SelectCHOISISSEZ(win.get(i).get(7));
passed = passed && Lapeyre_frMainPage.VerifyREFERENCE(win.get(i).get(8));(FROM HERE Validation Starts)
passed = passed && Lapeyre_frMainPage.VerifyQUANTITY(win.get(i).get(9));
...
passed = passed && Lapeyre_frMainPage.VerifyECO_PARTPrice(win.get(i).get(23));
Lapeyre_frMainPage.ClickCREAMIXReinit();(Reset button to test next scenario)
if(passed) {
test1.pass("Scenario " + win.get(i).get(0) + " is passed");
} else {
test1.fail("Scenario " + win.get(i).get(0) + " is failed");
}
System.out.println("########### Test End ##############");
extent.flush();----------(Extent report over)
}

Write unit tests with TestNG in Eclipse

The class MobileStorage is the implementation of a retro mobile phone's inbox. The inbox thereby is dened to hold a predened maximum capacity of messages with up to 160 characters per message. The following operations are supported and need to be tested:
saveMessage: Stores a new text message to the inbox at the next free position. In case the
message text is longer than 160 characters, the message is splitted and stored on multiple
storage positions.
deleteMessage: Removes the oldest (rst) mobile message from the inbox.
listMessages: Prints a readable representation of all currently stored messages. Messages that were stored in multiple parts are joined together for representation.
I need to do some Unit Testing on this code that i attached. Im not very familiar with TestNG and unit testing in general, can you help me with some examples of testing that i can do?
mobile_storage\src\main\java\MobileMessage.java - https://pastebin.com/RxNcgnSi
/**
* Represents a mobile text message.
*/
public class MobileMessage {
//stores the content of this messages
private final String text;
//in case of multi-part-messages, stores the preceding message
//is null in case of single message
private MobileMessage predecessor;
public MobileMessage(String text, MobileMessage predecessor) {
this.text = text;
this.predecessor = predecessor;
}
public String getText() {
return text;
}
public MobileMessage getPredecessor() {
return predecessor;
}
public void setPredecessor(MobileMessage predecessor) {
this.predecessor = predecessor;
}
}
mobile_storage\src\main\java\MobileStorage.java - https://pastebin.com/wuqKgvFD
import org.apache.commons.lang.StringUtils;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.IntStream;
/**
* Represents the message inbox of a mobile phone.
* Each storage position in the inbox can store a message with 160 characters at most.
* Messages are stored with increasing order (oldest first).
*/
public class MobileStorage {
final static int MAX_MESSAGE_LENGTH = 160;
private MobileMessage[] inbox;
private int occupied = 0;
/**
* Creates a message inbox that can store {#code storageSize} mobile messages.
* #throws IllegalArgumentException in case the passed {#code storageSize} is zero or less
*/
public MobileStorage(int storageSize) {
if(storageSize < 1) {
throw new IllegalArgumentException("Storage size must be greater than 0");
}
this.inbox = new MobileMessage[storageSize];
}
/**
* Stores a new text message to the inbox.
* In case the message text is longer than {#code MAX_MESSAGE_LENGTH}, the message is splitted and stored on multiple storage positions.
* #param message a non-empty message text
* #throws IllegalArgumentException in case the given message is empty
* #throws RuntimeException in case the available storage is too small for storing the complete message text
*/
public void saveMessage(String message) {
if(StringUtils.isBlank(message)) {
throw new IllegalArgumentException("Message cannot be null or empty");
}
int requiredStorage = (int) Math.ceil((double) message.length() / MAX_MESSAGE_LENGTH);
if(requiredStorage > inbox.length || (inbox.length - occupied) <= requiredStorage) {
throw new RuntimeException("Storage Overflow");
}
MobileMessage predecessor = null;
for(int i = 0; i < requiredStorage; i++) {
int from = i * MAX_MESSAGE_LENGTH;
int to = Math.min((i+1) * MAX_MESSAGE_LENGTH, message.length());
String messagePart = message.substring(from, to);
MobileMessage mobileMessage = new MobileMessage(messagePart, predecessor);
inbox[occupied] = mobileMessage;
occupied++;
predecessor = mobileMessage;
}
}
/**
* Returns the number of currently stored mobile messages.
*/
public int getOccupied() {
return occupied;
}
/**
* Removes the oldest (first) mobile message from the inbox.
*
* #return the deleted message
* #throws RuntimeException in case there are currently no messages stored
*/
public String deleteMessage() {
if(occupied == 0) {
throw new RuntimeException("There are no messages in the inbox");
}
MobileMessage first = inbox[0];
IntStream.range(1, occupied).forEach(index -> inbox[index-1] = inbox[index]);
inbox[occupied] = null;
inbox[0].setPredecessor(null);
occupied--;
return first.getText();
}
/**
* Returns a readable representation of all currently stored messages.
* Messages that were stored in multiple parts are joined together for representation.
* returns an empty String in case there are currently no messages stored
*/
public String listMessages() {
return Arrays.stream(inbox)
.filter(Objects::nonNull)
.collect(StringBuilder::new, MobileStorage::foldMessage, StringBuilder::append)
.toString();
}
private static void foldMessage(StringBuilder builder, MobileMessage message) {
if (message.getPredecessor() == null && builder.length() != 0) {
builder.append('\n');
}
builder.append(message.getText());
}
}
You will have to set up testNG . The way I test with testNG is with Eclipse and maven (dependency management). Once you have that , you can import classes in a test.java file in src folder under maven-Java project of eclipse.
You may need to adjust the code and import necessary classes for testNG. Here is the official documentation of testNG and here is the assert class.
I have tried to include some test cases. Hope this helps
Your test.java may look something like this
import yourPackage.MobileStorage;
import yourPackage. MobileMessage;
public class test{
#BeforeTest
public void prepareInstance(){
MobileStorage mobStg = new MobileStorage();
MobileMessage mobMsg = new MobileMessage();
}
//test simple msg
#Test
public void testSave(){
mobStg.saveMessage("hello")
assert.assertEquals("hello", mobMsg.getText())
}
//test msg with more chars
#Test
public void testMsgMoreChar(){
mobStg.saveMessage("messageWithMoreThan160Char")
//access messagepart here somehow, i am not sure of that
assert.assertEquals(mobMsg.getText(), mobStg.messagePart);
//access message here somehow. This will test listMessages() and concatenation of msgs
assert.assertEquals(mobStg.message, mobStg.listMessages())
}
//test deletion of msg
#Test
public void testDelete(){
mobStg.deleteMessage();
assert.assertEquals(null, mobMsg.getPredecessor())
}
}

Customize Interactive Brokers' reqIds() and reqMktData() Java methods

I am trying to write customized code within Interactive Brokers' Java API. There are a bunch of methods that get sent to TWS via the eClientSocket object. Two examples are reqIds() and reqMktData(). These are both void methods, so they do not return anything. Instead, they 'activate' methods written within the class that invokes them (in this case, SampleFrame). These methods are also void, in that they don't return any data. Instead, code is written within these methods (nextValidId() and tickPrice() respectively) to handle the data that is sent back from TWS (trader workstation).
I am having trouble creating a modified version of the nextValidId() and tickPrice() methods because reqIds() and reqMktData() don't actually specify these method names in their own code. I therefore cannot write a method called "tickPriceBlackBox()" which is called from within reqMktData(), or from within a copy of reqMktData() called reqMktDataBlackBox(). Again, there is no specific code within reqMktData() that can be modified to call a specific tickPriceBlackBox() method. It's as if code within TWS itself is hardwired to call the tickPrice() method, making it impossible for me to create a new method for returning price information.
Can anyone explain what is going on, or how to create a solution?
Here's some code:
void onReqMktData() {//requests market data from TWS / Interactive Brokers
// run m_orderDlg
m_orderDlg.init("Mkt Data Options", true, "Market Data Options", m_mktDataOptions);
m_orderDlg.show();
if( !m_orderDlg.m_rc ) {
return;
}
m_mktDataOptions = m_orderDlg.getOptions();
// req mkt data
m_client.reqMktData( m_orderDlg.m_id, m_orderDlg.m_contract,
m_orderDlg.m_genericTicks, m_orderDlg.m_snapshotMktData, m_mktDataOptions);
}
//Here is the reqMktData() method
public synchronized void reqMktData(int tickerId, Contract contract,
String genericTickList, boolean snapshot, List mktDataOptions) {
if (!m_connected) {
error(EClientErrors.NO_VALID_ID, EClientErrors.NOT_CONNECTED, "");
return;
}
if (m_serverVersion < MIN_SERVER_VER_SNAPSHOT_MKT_DATA && snapshot) {
error(tickerId, EClientErrors.UPDATE_TWS,
" It does not support snapshot market data requests.");
return;
}
if (m_serverVersion < MIN_SERVER_VER_UNDER_COMP) {
if (contract.m_underComp != null) {
error(tickerId, EClientErrors.UPDATE_TWS,
" It does not support delta-neutral orders.");
return;
}
}
if (m_serverVersion < MIN_SERVER_VER_REQ_MKT_DATA_CONID) {
if (contract.m_conId > 0) {
error(tickerId, EClientErrors.UPDATE_TWS,
" It does not support conId parameter.");
return;
}
}
if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) {
if (!IsEmpty(contract.m_tradingClass)) {
error(tickerId, EClientErrors.UPDATE_TWS,
" It does not support tradingClass parameter in reqMarketData.");
return;
}
}
final int VERSION = 11;
try {
// send req mkt data msg
send(REQ_MKT_DATA);
send(VERSION);
send(tickerId);
// send contract fields
if (m_serverVersion >= MIN_SERVER_VER_REQ_MKT_DATA_CONID) {
send(contract.m_conId);
}
send(contract.m_symbol);
send(contract.m_secType);
send(contract.m_expiry);
send(contract.m_strike);
send(contract.m_right);
if (m_serverVersion >= 15) {
send(contract.m_multiplier);
}
send(contract.m_exchange);
if (m_serverVersion >= 14) {
send(contract.m_primaryExch);
}
send(contract.m_currency);
if(m_serverVersion >= 2) {
send( contract.m_localSymbol);
}
if(m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) {
send( contract.m_tradingClass);
}
if(m_serverVersion >= 8 && BAG_SEC_TYPE.equalsIgnoreCase(contract.m_secType)) {
if ( contract.m_comboLegs == null ) {
send( 0);
}
else {
send( contract.m_comboLegs.size());
ComboLeg comboLeg;
for (int i=0; i < contract.m_comboLegs.size(); i ++) {
comboLeg = contract.m_comboLegs.get(i);
send( comboLeg.m_conId);
send( comboLeg.m_ratio);
send( comboLeg.m_action);
send( comboLeg.m_exchange);
}
}
}
if (m_serverVersion >= MIN_SERVER_VER_UNDER_COMP) {
if (contract.m_underComp != null) {
UnderComp underComp = contract.m_underComp;
send( true);
send( underComp.m_conId);
send( underComp.m_delta);
send( underComp.m_price);
}
else {
send( false);
}
}
if (m_serverVersion >= 31) {
/*
* Note: Even though SHORTABLE tick type supported only
* starting server version 33 it would be relatively
* expensive to expose this restriction here.
*
* Therefore we are relying on TWS doing validation.
*/
send( genericTickList);
}
if (m_serverVersion >= MIN_SERVER_VER_SNAPSHOT_MKT_DATA) {
send (snapshot);
}
// send mktDataOptions parameter
if(m_serverVersion >= MIN_SERVER_VER_LINKING) {
StringBuilder mktDataOptionsStr = new StringBuilder();
int mktDataOptionsCount = mktDataOptions == null ? 0 : mktDataOptions.size();
if( mktDataOptionsCount > 0) {
for( int i = 0; i < mktDataOptionsCount; ++i) {
TagValue tagValue = (TagValue)mktDataOptions.get(i);
mktDataOptionsStr.append( tagValue.m_tag);
mktDataOptionsStr.append( "=");
mktDataOptionsStr.append( tagValue.m_value);
mktDataOptionsStr.append( ";");
}
}
send( mktDataOptionsStr.toString());
}
}
catch( Exception e) {
error( tickerId, EClientErrors.FAIL_SEND_REQMKT, "" + e);
close();
}
}
//The key piece of this code, REQ_MKT_DATA, leads to a final int variable within the EClientSocket.java object, equal to 1. tickPrice() is not mentioned anywhere.
//This method provides stock price, but doesn't return a value. You have to put executable code within this one method. I cannot duplicate and change the name of this method (tickprice();) because none of my accessible code calls it, to my knowledge. It feels as if TWS is calling tickPrice from its end.
public void tickPrice( int tickerId, int field, double price, int canAutoExecute) {
// received price tick
String msg = EWrapperMsgGenerator.tickPrice( tickerId, field, price, canAutoExecute);
m_tickers.add( msg );
}
The tickPrice method is called from EReader which gets created in EClientSocket which knows the EWrapper implementation.
Basically you call the socket reqMktData method and it will send it to TWS. EReader will see the response on the socket as a tickPrice message and will send it to the Wrapper implementation.
If you want to handle it yourself then you do it inside the tickPrice method. It could be just as simple as passing the data to a method you define.
public void tickPrice( int tickerId, int field, double price, int canAutoExecute) {
handleTick(tickerId,field,price);
}
And then write your own handleTick method
Finally may have found an answer. I'm new to Java...these appear to be callback methods. A callback method receives information from some other source. Because the method is part of an object in OOP, the returned information (stock info in this case) is returned into the callback method. Any other code that is contained within the callback method is executed when the method is replied to.
I am still not clear on how these methods are activated if they haven't been specifically executed in the code on my machine. Does Interactive Broker's know to feed information back to this method inside my Java program? Seems logical.

How to log exceptions in Java?

There's a common problem I've come across a few times when logging exceptions in Java. There seem to be various different types to deal with. E.g. some wrap other exceptions and some don't have a message at all - only a type.
Most code I've seen logs an exception by using either getMessage() or toString(). But these methods don't always capture all the information needed to pinpoint the problem - other methods such as getCause() and getStackTrace() sometimes provide additional info.
For example, the exception I'm looking at right now in my Eclipse Inspect window is an InvocationTargetException. The exception itself has no cause, no message, no stacktrace ... but the target from getCause() is InvalidUseOfMatchersException, with these details populated.
So my question is: Given an exception of any type as an input, please provide a single method that will output a nicely formatted string containing all relevant information about the Exception (e.g. possibly recursively calling getCause() amongst other things?) Before posting, I was nearly going to have a stab at it myself but really don't want to reinvent the wheel - surely such a thing must have been done many times before...?
The java.util.logging package is standard in Java SE. Its Logger includes an overloaded log method that accepts Throwable objects.
It will log stacktraces of exceptions and their cause for you.
For example:
import java.util.logging.Level;
import java.util.logging.Logger;
[...]
Logger logger = Logger.getAnonymousLogger();
Exception e1 = new Exception();
Exception e2 = new Exception(e1);
logger.log(Level.SEVERE, "an exception was thrown", e2);
Will log:
SEVERE: an exception was thrown
java.lang.Exception: java.lang.Exception
at LogStacktrace.main(LogStacktrace.java:21)
Caused by: java.lang.Exception
at LogStacktrace.main(LogStacktrace.java:20)
Internally, this does exactly what #philipp-wendler suggests, by the way.
See the source code for SimpleFormatter.java. This is just a higher level interface.
What's wrong with the printStacktrace() method provided by Throwable (and thus every exception)? It shows all the info you requested, including the type, message, and stack trace of the root exception and all (nested) causes. In Java 7, it even shows you the information about "supressed" exceptions that might occur in a try-with-resources statement.
Of course you wouldn't want to write to System.err, which the no-argument version of the method does, so instead use one of the available overloads.
In particular, if you just want to get a String:
Exception e = ...
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionDetails = sw.toString();
If you happen to use the great Guava library, it provides a utility method doing this: com.google.common.base.Throwables#getStackTraceAsString(Throwable).
It should be quite simple if you are using LogBack or SLF4J. I do it as below
//imports
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//Initialize logger
Logger logger = LoggerFactory.getLogger(<classname>.class);
try {
//try something
} catch(Exception e){
//Actual logging of error
logger.error("some message", e);
}
A logging script that I have written some time ago might be of help, although it is not exactly what you want. It acts in a way like a System.out.println but with much more information about StackTrace etc. It also provides Clickable text for Eclipse:
private static final SimpleDateFormat extended = new SimpleDateFormat( "dd MMM yyyy (HH:mm:ss) zz" );
public static java.util.logging.Logger initLogger(final String name) {
final java.util.logging.Logger logger = java.util.logging.Logger.getLogger( name );
try {
Handler ch = new ConsoleHandler();
logger.addHandler( ch );
logger.setLevel( Level.ALL ); // Level selbst setzen
logger.setUseParentHandlers( false );
final java.util.logging.SimpleFormatter formatter = new SimpleFormatter() {
#Override
public synchronized String format(final LogRecord record) {
StackTraceElement[] trace = new Throwable().getStackTrace();
String clickable = "(" + trace[ 7 ].getFileName() + ":" + trace[ 7 ].getLineNumber() + ") ";
/* Clickable text in Console. */
for( int i = 8; i < trace.length; i++ ) {
/* 0 - 6 is the logging trace, 7 - x is the trace until log method was called */
if( trace[ i ].getFileName() == null )
continue;
clickable = "(" + trace[ i ].getFileName() + ":" + trace[ i ].getLineNumber() + ") -> " + clickable;
}
final String time = "<" + extended.format( new Date( record.getMillis() ) ) + "> ";
StringBuilder level = new StringBuilder("[" + record.getLevel() + "] ");
while( level.length() < 15 ) /* extend for tabby display */
level.append(" ");
StringBuilder name = new StringBuilder(record.getLoggerName()).append(": ");
while( name.length() < 15 ) /* extend for tabby display */
name.append(" ");
String thread = Thread.currentThread().getName();
if( thread.length() > 18 ) /* trim if too long */
thread = thread.substring( 0, 16 ) + "...";
else {
StringBuilder sb = new StringBuilder(thread);
while( sb.length() < 18 ) /* extend for tabby display */
sb.append(" ");
thread = sb.insert( 0, "Thread " ).toString();
}
final String message = "\"" + record.getMessage() + "\" ";
return level + time + thread + name + clickable + message + "\n";
}
};
ch.setFormatter( formatter );
ch.setLevel( Level.ALL );
} catch( final SecurityException e ) {
e.printStackTrace();
}
return logger;
}
Notice this outputs to the console, you can change that, see http://docs.oracle.com/javase/1.4.2/docs/api/java/util/logging/Logger.html for more information on that.
Now, the following will probably do what you want. It will go through all causes of a Throwable and save it in a String. Note that this does not use StringBuilder, so you can optimize by changing it.
Throwable e = ...
String detail = e.getClass().getName() + ": " + e.getMessage();
for( final StackTraceElement s : e.getStackTrace() )
detail += "\n\t" + s.toString();
while( ( e = e.getCause() ) != null ) {
detail += "\nCaused by: ";
for( final StackTraceElement s : e.getStackTrace() )
detail += "\n\t" + s.toString();
}
Regards,
Danyel
You can also use Apache's ExceptionUtils.
Example:
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.log4j.Logger;
public class Test {
static Logger logger = Logger.getLogger(Test.class);
public static void main(String[] args) {
try{
String[] avengers = null;
System.out.println("Size: "+avengers.length);
} catch (NullPointerException e){
logger.info(ExceptionUtils.getFullStackTrace(e));
}
}
}
Console output:
java.lang.NullPointerException
at com.aimlessfist.avengers.ironman.Test.main(Test.java:11)
Something that I do is to have a static method that handles all exceptions and I add the log to a JOptionPane to show it to the user, but you could write the result to a file in FileWriter wraped in a BufeeredWriter.
For the main static method, to catch the Uncaught Exceptions I do:
SwingUtilities.invokeLater( new Runnable() {
#Override
public void run() {
//Initializations...
}
});
Thread.setDefaultUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException( Thread t, Throwable ex ) {
handleExceptions( ex, true );
}
}
);
And as for the method:
public static void handleExceptions( Throwable ex, boolean shutDown ) {
JOptionPane.showMessageDialog( null,
"A CRITICAL ERROR APPENED!\n",
"SYSTEM FAIL",
JOptionPane.ERROR_MESSAGE );
StringBuilder sb = new StringBuilder(ex.toString());
for (StackTraceElement ste : ex.getStackTrace()) {
sb.append("\n\tat ").append(ste);
}
while( (ex = ex.getCause()) != null ) {
sb.append("\n");
for (StackTraceElement ste : ex.getStackTrace()) {
sb.append("\n\tat ").append(ste);
}
}
String trace = sb.toString();
JOptionPane.showMessageDialog( null,
"PLEASE SEND ME THIS ERROR SO THAT I CAN FIX IT. \n\n" + trace,
"SYSTEM FAIL",
JOptionPane.ERROR_MESSAGE);
if( shutDown ) {
Runtime.getRuntime().exit( 0 );
}
}
In you case, instead of "screaming" to the user, you could write a log like I told you before:
String trace = sb.toString();
File file = new File("mylog.txt");
FileWriter myFileWriter = null;
BufferedWriter myBufferedWriter = null;
try {
//with FileWriter(File file, boolean append) you can writer to
//the end of the file
myFileWriter = new FileWriter( file, true );
myBufferedWriter = new BufferedWriter( myFileWriter );
myBufferedWriter.write( trace );
}
catch ( IOException ex1 ) {
//Do as you want. Do you want to use recursive to handle
//this exception? I don't advise that. Trust me...
}
finally {
try {
myBufferedWriter.close();
}
catch ( IOException ex1 ) {
//Idem...
}
try {
myFileWriter.close();
}
catch ( IOException ex1 ) {
//Idem...
}
}
I hope I have helped.
Have a nice day. :)
Best practice is to log the whole exception:
log.error("Our custom message", ex);
By logging the developer message together with the whole exception object, we can see the developer message followed by the exception name and message, then the stack trace.
This gives us a complete picture of what methods were invoked when the exception occurred, down to the library level.
Reference/credits:
https://medium.com/w-logs/how-to-log-exception-properly-6aa80b62ff8a

How can we print line numbers to the log in java

How to print line numbers to the log. Say when outputting some information to the log, I also want to print the line number where that output is in the source code. As we can see in the stack trace, it displays the line number where the exception has occurred. Stack trace is available on the exception object.
Other alternative could be like manually including the line number when printing to the log. Is there any other way?
From Angsuman Chakraborty (archived) :
/** Get the current line number.
* #return int - Current line number.
*/
public static int getLineNumber() {
return Thread.currentThread().getStackTrace()[2].getLineNumber();
}
We ended up using a custom class like this for our Android work:
import android.util.Log;
public class DebugLog {
public final static boolean DEBUG = true;
public static void log(String message) {
if (DEBUG) {
String fullClassName = Thread.currentThread().getStackTrace()[2].getClassName();
String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1);
String methodName = Thread.currentThread().getStackTrace()[2].getMethodName();
int lineNumber = Thread.currentThread().getStackTrace()[2].getLineNumber();
Log.d(className + "." + methodName + "():" + lineNumber, message);
}
}
}
Quick and dirty way:
System.out.println("I'm in line #" +
new Exception().getStackTrace()[0].getLineNumber());
With some more details:
StackTraceElement l = new Exception().getStackTrace()[0];
System.out.println(
l.getClassName()+"/"+l.getMethodName()+":"+l.getLineNumber());
That will output something like this:
com.example.mytest.MyClass/myMethod:103
I am compelled to answer by not answering your question. I'm assuming that you are looking for the line number solely to support debugging. There are better ways. There are hackish ways to get the current line. All I've seen are slow. You are better off using a logging framework like that in java.util.logging package or log4j. Using these packages you can configure your logging information to include context down to the class name. Then each log message would be unique enough to know where it came from. As a result, your code will have a 'logger' variable that you call via
logger.debug("a really descriptive message")
instead of
System.out.println("a really descriptive message")
Log4J allows you to include the line number as part of its output pattern. See http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html for details on how to do this (the key element in the conversion pattern is "L"). However, the Javadoc does include the following:
WARNING Generating caller location
information is extremely slow. It's
use should be avoided unless execution
speed is not an issue.
The code posted by #simon.buchan will work...
Thread.currentThread().getStackTrace()[2].getLineNumber()
But if you call it in a method it will always return the line number of the line in the method so rather use the code snippet inline.
I would recommend using a logging toolkit such as log4j. Logging is configurable via properties files at runtime, and you can turn on / off features such as line number / filename logging.
Looking at the javadoc for the PatternLayout gives you the full list of options - what you're after is %L.
I use this little method that outputs the trace and line number of the method that called it.
Log.d(TAG, "Where did i put this debug code again? " + Utils.lineOut());
Double click the output to go to that source code line!
You might need to adjust the level value depending on where you put your code.
public static String lineOut() {
int level = 3;
StackTraceElement[] traces;
traces = Thread.currentThread().getStackTrace();
return (" at " + traces[level] + " " );
}
You can't guarantee line number consistency with code, especially if it is compiled for release. I would not recommend using line numbers for that purpose anyway, it would be better to give a payload of the place where the exception was raised (the trivial method being to set the message to include the details of the method call).
You might like to look at exception enrichment as a technique to improve exception handling
http://tutorials.jenkov.com/java-exception-handling/exception-enrichment.html
If it's been compiled for release this isn't possible. You might want to look into something like Log4J which will automatically give you enough information to determine pretty closely where the logged code occurred.
first the general method (in an utility class, in plain old java1.4 code though, you may have to rewrite it for java1.5 and more)
/**
* Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils" and aclass. <br />
* Allows to get past a certain class.
* #param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils.
* #return "[class#method(line)]: " (never empty, because if aclass is not found, returns first class past StackTraceUtils)
*/
public static String getClassMethodLine(final Class aclass) {
final StackTraceElement st = getCallingStackTraceElement(aclass);
final String amsg = "[" + st.getClassName() + "#" + st.getMethodName() + "(" + st.getLineNumber()
+")] <" + Thread.currentThread().getName() + ">: ";
return amsg;
}
Then the specific utility method to get the right stackElement:
/**
* Returns the first stack trace element of the first class not equal to "StackTraceUtils" or "LogUtils" and aClass. <br />
* Stored in array of the callstack. <br />
* Allows to get past a certain class.
* #param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils.
* #return stackTraceElement (never null, because if aClass is not found, returns first class past StackTraceUtils)
* #throws AssertionFailedException if resulting statckTrace is null (RuntimeException)
*/
public static StackTraceElement getCallingStackTraceElement(final Class aclass) {
final Throwable t = new Throwable();
final StackTraceElement[] ste = t.getStackTrace();
int index = 1;
final int limit = ste.length;
StackTraceElement st = ste[index];
String className = st.getClassName();
boolean aclassfound = false;
if(aclass == null) {
aclassfound = true;
}
StackTraceElement resst = null;
while(index < limit) {
if(shouldExamine(className, aclass) == true) {
if(resst == null) {
resst = st;
}
if(aclassfound == true) {
final StackTraceElement ast = onClassfound(aclass, className, st);
if(ast != null) {
resst = ast;
break;
}
}
else
{
if(aclass != null && aclass.getName().equals(className) == true) {
aclassfound = true;
}
}
}
index = index + 1;
st = ste[index];
className = st.getClassName();
}
if(isNull(resst)) {
throw new AssertionFailedException(StackTraceUtils.getClassMethodLine() + " null argument:" + "stack trace should null"); //$NON-NLS-1$
}
return resst;
}
static private boolean shouldExamine(String className, Class aclass) {
final boolean res = StackTraceUtils.class.getName().equals(className) == false && (className.endsWith(LOG_UTILS
) == false || (aclass !=null && aclass.getName().endsWith(LOG_UTILS)));
return res;
}
static private StackTraceElement onClassfound(Class aclass, String className, StackTraceElement st) {
StackTraceElement resst = null;
if(aclass != null && aclass.getName().equals(className) == false)
{
resst = st;
}
if(aclass == null)
{
resst = st;
}
return resst;
}
Here is the logger that we use.
it wraps around Android Logger and display class name, method name and line number.
http://www.hautelooktech.com/2011/08/15/android-logging/
Look at this link. In that method you can jump to your line code, when you double click on LogCat's row.
Also you can use this code to get line number:
public static int getLineNumber()
{
int lineNumber = 0;
StackTraceElement[] stackTraceElement = Thread.currentThread()
.getStackTrace();
int currentIndex = -1;
for (int i = 0; i < stackTraceElement.length; i++) {
if (stackTraceElement[i].getMethodName().compareTo("getLineNumber") == 0)
{
currentIndex = i + 1;
break;
}
}
lineNumber = stackTraceElement[currentIndex].getLineNumber();
return lineNumber;
}
private static final int CLIENT_CODE_STACK_INDEX;
static {
// Finds out the index of "this code" in the returned stack Trace - funny but it differs in JDK 1.5 and 1.6
int i = 0;
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
i++;
if (ste.getClassName().equals(Trace.class.getName())) {
break;
}
}
CLIENT_CODE_STACK_INDEX = i;
}
private String methodName() {
StackTraceElement ste=Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX+1];
return ste.getMethodName()+":"+ste.getLineNumber();
}
These all get you the line numbers of your current thread and method which work great if you use a try catch where you are expecting an exception. But if you want to catch any unhandled exception then you are using the default uncaught exception handler and current thread will return the line number of the handler function, not the class method that threw the exception. Instead of using Thread.currentThread() simply use the Throwable passed in by the exception handler:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
if(fShowUncaughtMessage(e,t))
System.exit(1);
}
});
In the above use e.getStackTrace()[0] in your handler function (fShowUncaughtMessage) to get the offender.
Below code is tested code for logging line no class name and method name from where logging method is called
public class Utils {
/*
* debug variable enables/disables all log messages to logcat
* Useful to disable prior to app store submission
*/
public static final boolean debug = true;
/*
* l method used to log passed string and returns the
* calling file as the tag, method and line number prior
* to the string's message
*/
public static void l(String s) {
if (debug) {
String[] msg = trace(Thread.currentThread().getStackTrace(), 3);
Log.i(msg[0], msg[1] + s);
} else {
return;
}
}
/*
* l (tag, string)
* used to pass logging messages as normal but can be disabled
* when debug == false
*/
public static void l(String t, String s) {
if (debug) {
Log.i(t, s);
} else {
return;
}
}
/*
* trace
* Gathers the calling file, method, and line from the stack
* returns a string array with element 0 as file name and
* element 1 as method[line]
*/
public static String[] trace(final StackTraceElement e[], final int level) {
if (e != null && e.length >= level) {
final StackTraceElement s = e[level];
if (s != null) { return new String[] {
e[level].getFileName(), e[level].getMethodName() + "[" + e[level].getLineNumber() + "]"
};}
}
return null;
}
}
The stackLevel depends on depth you call this method. You can try from 0 to a large number to see what difference.
If stackLevel is legal, you will get string like java.lang.Thread.getStackTrace(Thread.java:1536)
public static String getCodeLocationInfo(int stackLevel) {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
if (stackLevel < 0 || stackLevel >= stackTraceElements.length) {
return "Stack Level Out Of StackTrace Bounds";
}
StackTraceElement stackTraceElement = stackTraceElements[stackLevel];
String fullClassName = stackTraceElement.getClassName();
String methodName = stackTraceElement.getMethodName();
String fileName = stackTraceElement.getFileName();
int lineNumber = stackTraceElement.getLineNumber();
return String.format("%s.%s(%s:%s)", fullClassName, methodName, fileName, lineNumber);
}
This is exactly the feature I implemented in this lib
XDDLib. (But, it's for android)
Lg.d("int array:", intArrayOf(1, 2, 3), "int list:", listOf(4, 5, 6))
One click on the underlined text to navigate to where the log command is
That StackTraceElement is determined by the first element outside this library. Thus, anywhere outside this lib will be legal, including lambda expression, static initialization block, etc.
For anyone wondering, the index in the getStackTrace()[3] method signals the amount of threads the triggering line travels until the actual .getStackTrace() method excluding the executing line.
This means that if the Thread.currentThread().getStackTrace()[X].getLineNumber(); line is executed from 3 nested methods above, the index number must be 3.
Example:
First layer
private static String message(String TAG, String msg) {
int lineNumber = Thread.currentThread().getStackTrace()[3].getLineNumber();
return ".(" + TAG + ".java:"+ lineNumber +")" + " " + msg;
}
Second Layer
private static void print(String s) {
System.out.println(s);
}
Third Layer
public static void normal(
String TAG,
String message
) {
print(
message(
TAG,
message
)
);
}
Executing Line:
Print.normal(TAG, "StatelessDispatcher");
As someone that has not received any formal education on IT, this has been mind opening on how compilers work.
This is the code which prints the line number.
Thread.currentThread().getStackTrace()[2].getLineNumber()
Create a global public static method to make printing Logs easier.
public static void Loge(Context context, String strMessage, int strLineNumber) {
Log.e(context.getClass().getSimpleName(), strLineNumber + " : " + strMessage);
}
My way it works for me
String str = "select os.name from os where os.idos="+nameid; try {
PreparedStatement stmt = conn.prepareStatement(str);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
a = rs.getString("os.n1ame");//<<<----Here is the ERROR
}
stmt.close();
} catch (SQLException e) {
System.out.println("error line : " + e.getStackTrace()[2].getLineNumber());
return a;
}
you can use -> Reporter.log("");

Categories