Logging with Logger under Android - java

I've noticed that the following works on PC but not inside the Android simulator.
Logger logger = Logger.getLogger("foo");
logger.log(Level.INFO, "Number is: {0}", new Object[]{new Integer(42)});
It just prints
Number is: {0}
Why does this fail for android?

I found a solution in a roundabout way. Ultimately, I think there is a Formatter somewhere in the default android logging implementation which is rendering just the message, ignoring the params. You should be able to use the Logging API to install a formatter of your own design.
I had already installed a new Handler for a totally separate reason. The source I used is available here: http://4thline.org/projects/download/misc/
The handler is in the teleal-common-1.0.14-source.tar.gz archive. Follow the path to src\main\java\org\fourthline\android\util\FixedAndroidHandler.java.
This site also provides code to install this handler, but it's in a different archive: sash-1.0-SNAPSHOT.tar.gz. Locate 1.0\src\main\java\org\teleal\common\logging\LoggingUtil.java.
You can install this handler by making this call somewhere in your app startup code:
LoggingUtil.resetRootHandler(new FixedAndroidHandler());
What I found was that the Formatter for this Handler is embedded as an anonymous class inside the Handler. How convenient. I could see that the Formatter did not process the parameters passed in via the LogRecord. I just added an "else-if" condition:
private static final Formatter THE_FORMATTER = new Formatter() {
#Override
public String format(LogRecord r) {
String msg = r.getMessage();
Object[] params = r.getParameters();
Throwable thrown = r.getThrown();
if (thrown != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
sw.write(r.getMessage());
sw.write("\n");
thrown.printStackTrace(pw);
pw.flush();
return sw.toString();
} else if ((params != null) && (params.length > 0) && (msg.indexOf("{0") >= 0)) {
return MessageFormat.format(msg, params);
} else {
return r.getMessage();
}
}
};
The if test is consistent with other log formatting code I've seen. In theory you should be able to take a more direct approach of installing a similar Formatter to an existing Handler. I haven't tried this myself due to the fact that the above solution is working for me.

You can accomplish the same String formatting using the static String.format(String format, Object... args) method:
Log.d(TAG, String.format("Number is: %d", new Integer(42)));

Use:
android.util.Log.i(TAG, "Number is: " + number);
See http://developer.android.com/reference/android/util/Log.html

Related

Logging access to Java servlet

I'm currently developing a Java Web application using Servlets. What I need to do is log to a file every access made to the website. To do that, I used Filters. So far, I've made it to the point where I can print everything to the console.
What I now need to do is store that into a file with a maximum of 10.000 entries up to 30 days old (if the maximum entries is achieved, the oldest ones are replaced when a new one is written).
How can I do that?
P.S: I cannot use a database for this assignment
Edit: I am not using a web framework. I can use logging frameworks.
So, this question actually prompted me to investigate whether any of the popular logging frameworks can actually do the task as requested.
While most do rolling logs based on file size and date/time, none of them had an easy way to do a rolling log based on entries in the log file. Also, existing logging frameworks typically store each day (and sometimes smaller units of time) in their own separate file, making for efficient cleanup based on date/time.
With a requirement for a maximum number of lines inside a single file, this necessitates reading the entire file into memory (very inefficient!). When everything, past and present is being written to a single file, removing older entries requires parsing each line for the date/time that entry was written (also, inefficient!).
Below is a simple program to demonstrate that this can be done, but there are some serious problems with this approach:
Not thread safe (if two threads try to read/write an entry simultaneously, one will be clobbered and the message will be skipped)
Slurping is bad (ten thousand entries is a lot: can the server slurp all that into memory?)
This is probably suitable for a toy project, a demonstration, or a school assignment.
This is NOT suitable for production applications, or really anything on the web that more than one person is going to use at a time.
In short, if you try to use a handi-craft program that you found on the internet for a mission-critical application that other people depend on, you are going to get exactly what you deserve.
public static void main(final String[] args) throws Exception
{
final File logFile = new File("C:/", "EverythingInOneBigGiant.log");
final int maxDays = 30;
final int maxEntries = 10000;
while (true)
{
// Just log the current time for this example, also makes parsing real simple
final String msg = Instant.now().toString();
slurpAndParse(logFile, msg, maxDays, maxEntries);
// Wait a moment, before writing another entry
Thread.sleep(750);
}
}
private static void slurpAndParse(final File f, final String msg, final int maxDays, final int maxEntries)
throws Exception
{
// Slurp entire file into this buffer (possibly very large!)
// Could crash your server if you run out of memory
final StringBuffer sb = new StringBuffer();
if (f.exists() && f.isFile())
{
final LocalDateTime now = LocalDateTime.now();
final long totalLineCount = Files.lines(Paths.get(f.getAbsolutePath())).count();
final long startAtLine = (totalLineCount < maxEntries ? 0 : (totalLineCount - maxEntries) + 1);
long currentLineCount = 0;
try (final BufferedReader br = new BufferedReader(new FileReader(f)))
{
String line;
while (null != (line = br.readLine()))
{
// Ignore all lines before the start counter
if (currentLineCount < startAtLine)
{
++currentLineCount;
continue;
}
// Parsing log data... while writing to the same log... ugh... how hideous
final LocalDateTime lineDate = LocalDateTime.parse(line, DateTimeFormatter.ISO_ZONED_DATE_TIME);
final Duration timeBetween = Duration.between(lineDate, now);
// ... or maybe just use Math.abs() here? I defer to the date/time buffs
final long dayDiff = (timeBetween.isNegative() ? timeBetween.negated() : timeBetween).toDays();
// Only accept lines less than the max age in days
if (dayDiff <= maxDays)
{
sb.append(line);
sb.append(System.lineSeparator());
}
}
}
}
System.out.println(msg);
// Add the new log entry
sb.append(msg);
sb.append(System.lineSeparator());
writeLog(f, sb.toString());
}
private static void writeLog(final File f, final String content) throws IOException
{
try (final Writer out = new FileWriter(f))
{
out.write(content);
}
}

Print log message in the same line [duplicate]

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.

Verbose Rexster output/logging on error `null`

I use Titan in a small Ubuntu server cloud with size 3 and deployed a Rexster extension to to $TITAN_HOME/ext. However, if I try to call an endpoint of the extension I get
{"message":"An error occurred while generating the response object","error":null}
which is not very helpful. How can I get more verbose output to see what is going wrong here? In addition, error null seems strange to me. Any ideas what can cause it?
edit:
I wrapped the whole execution of the extension that causes the errors in a try-catch-everything block:
#ExtensionNaming(
namespace = GraphityExtension.EXT_NAMESPACE,
name = "unfollow")
public class RemoveFollowshipExtension extends GraphityExtension {
#ExtensionDefinition(
extensionPoint = ExtensionPoint.GRAPH)
#ExtensionDescriptor(
description = "Removes a followship between two users.")
public
ExtensionResponse
unfollow(
#RexsterContext RexsterResourceContext content,
#RexsterContext Graph graph,
#ExtensionRequestParameter(
name = "following",
description = "identifier of the user following") String idFollowing,
#ExtensionRequestParameter(
name = "followed",
description = "identifier of the user followed") String idFollowed) {
try {
Graphity graphity = getGraphityInstance((TitanGraph) graph);
Map<String, String> map = new HashMap<String, String>();
try {
map.put(KEY_RESPONSE_VALUE, String.valueOf(graphity
.removeFollowship(idFollowing, idFollowed)));
return ExtensionResponse.ok(new JSONObject(map));
} catch (UnknownFollowingIdException | UnknownFollowedIdException e) {
return ExtensionResponse.error(e);
}
} catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
return ExtensionResponse.error(sw.toString());
}
}
but keep getting
{"message":"","error":null}
on client side. The rexstitan.log contains warnings concerning these errors:
com.tinkerpop.rexster.GraphResource - The [graphity:unfollow+*] extension raised an error response.
which is nice to know but not very detailed.
You usually get that error if there is some failure during invocation of your extension. Usually, the console where Rexster is running should provide some log messages that explain the cause and have a stack trace.
In the event that you are not seeing those for some reason, I would try to do your own logging in your extension and possibly trap exceptions in your code more generally (and logging in the catch clause) until you can see the error.

Pinning .jar files to the taskbar in windows 7

My question is an extension on another question already answered, https://superuser.com/questions/257467/windows-7-how-to-pin-a-jar-to-the-taskbar
Is there a way to pin a jar to the taskbar, and have the window generated by the jar register as a different process, thus creating a different icon in the task bar? because as it stands, using any of the methods listed in the answer to the above question, you end up with a shortcut that can be pinned. but it is just a shortcut and only that, not the program itself. Im willing to try anything at this point as it is beginning to be very bothersome. not only does it look unprofessional, it uses up unnecessary screen real estate. As I know someone is going to ask what else I've tried, here's a bit of code i tried to run in c# to launch the jar, but of course, it does the same thing, registering the new process as a new process. (should have thought that one through.)
string strCmdText;
strCmdText = "-jar ImgurDownloader.jar";
Process process = new Process();
process.StartInfo.Arguments = strCmdText;
process.StartInfo.FileName = "javaw";
process.StartInfo.UseShellExecute = false;
process.Start();
so then I tried this:
string strCmdText;
strCmdText = "-jar ImgurDownloader.jar";
Process process = Process.GetCurrentProcess();
process.StartInfo.Arguments = strCmdText;
process.StartInfo.FileName = "javaw";
process.StartInfo.UseShellExecute = false;
process.Start();
and yet still, even if i try and replace the current process, it comes across as a new process, and thus a second icon in the taskbar. Please excuse my possibly short tone, the frustration is starting to kick in after a couple weeks.
Edit: have also tried setting the UAMID (User Application Model ID) using the JNA library to access shel32.dll's functions. The following is the code in the jar
public static void setCurrentProcessExplicitAppUserModelID(final String appID) {
if (SetCurrentProcessExplicitAppUserModelID(new WString(appID)).longValue() != 0)
throw new RuntimeException("unable to set current process explicit AppUserModelID to: " + appID);
}
public static String getCurrentProcessExplicitAppUserModelID() {
final PointerByReference r = new PointerByReference();
if (GetCurrentProcessExplicitAppUserModelID(r).longValue() == 0) {
final Pointer p = r.getValue();
return p.getString(0, true); // here we leak native memory by
// lazyness
}
return "N/A";
}
private static native NativeLong GetCurrentProcessExplicitAppUserModelID(PointerByReference appID);
private static native NativeLong SetCurrentProcessExplicitAppUserModelID(WString appID);
static {
Native.register("shell32");
}
then just call the set method. Tested with the get method, however,
NOTE: getCurrentProcessExplicitAppUserModelID is a lazy method and breaks things later on if used.
then in the C# Wrapper,
[DllImport("shell32.dll")]
public static extern int SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
static void Main()
{
int der = SetCurrentProcessExplicitAppUserModelID("MAndWorks.ImgurDownloader.ImgurDownloader.2.0.0.0");
string strCmdText;
Console.WriteLine(der);
strCmdText = "-jar ImgurDownloader.jar";
Process process = new Process();
process.StartInfo.Arguments = strCmdText;
process.StartInfo.FileName = "javaw";
process.StartInfo.UseShellExecute = false;
process.Start();
process.WaitForExit();
Console.WriteLine("AWFURA");
}

java.lang.nosuchfielderror in j2me app

Hey Hi Friends I am created one j2me app. it runs perfectly in Emulator but in Mobile it showing error like java.lang.nosuchfielderror:No such field HEADERS.[[Ljava/lang/String;.
Why this happening with mobile, it runs good in emulator......
Please help me to remove this error......
public String connectPhoneName() throws Exception{
String url = "http://122.170.122.186/Magic/getPhonetype.jsp";
String phoneType;
if ((conn = connectHttp.connect(url, HEADERS)) != null) {
if ((in = connectHttp.getDataInputStream(conn)) != null) {
byte[] data = connectHttp.readDATA(in, 100);
phoneType = new String(data);
System.out.println("DATA : " + phoneType);
} else {
throw new Exception("ERROR WHILE OPENING INPUTSTREAM");
}
} else {
throw new Exception("COULD NOT ESTABLISH CONNECTION TO THE SERVER");
}
return phoneType;
}
In this code i have used HEADERS.
It looks like your app is using some (I guess) or static final or final field of some library class that does not exist in the profile of Java ME your mobile device implements.
But I can't figure out where that field comes from. Perhaps you should search your codebase for use of "HEADER" as an identifier ...
If the HEADER field is properly declared in your codebase (your MagiDEF interface) and the code you showed is using the HEADER from that interface, then you must have something wrong with your build or deployment process. Specifically, you are not deploying the version of MagiDEF that your code (above) has been compiled against. Maybe you've got an old version of something in some JAR file?
Basically, the error indicates that you have a binary incompatibility between some of the classes / interfaces that make up your app.

Categories