I have seen like a million different log functions , like log.i , log.v , log.d .
I just want to output a simple string on the log some times in my code to see if everything is working ok for debugging.
What is the clean way to do that?
You can use Log to track the logs in your application code.
Log API is for sending log output.
Generally, use the Log.v() Log.d() Log.i() Log.w() and Log.e() methods.
The order in terms of verbosity(wordiness), from least to most is ERROR, WARN, INFO, DEBUG, VERBOSE. Otherwise more or less they are same.
Verbose should never be compiled into an application except during development.
Debug logs are compiled in but stripped at runtime.
Error, warning and info logs are always kept.
example
String TAG = "value of i = ";
for(int i = 0; i<=10 i++)
{
Log.i(TAG, i+"");
}
this will print the 10 numbers in your log.i (info).
log.d
is for debug
log.e
is for error
and so on. here is a link to study more about log
Log.d("tag","the string youd like");
log.d is for the debug list of LogCat
When you change the letters after log. you are basically setting the severity of this log record:
I => Info
V => Verbose
D => Debug
E => Error
Take a look at this picture for all the different kinds of log records:
So use .d for simple debugging records like this:
Log.d (TAG, "the message you want to out put");
While I always set the TAG at the begging of the class like this:
static final String TAG = YouCurrentActivity.class.getSimpleName();
#donparalias great question
The Most easiest way:
public static final String LOG_TAG = "Facebook";
public void onFacebookError(FacebookError error)
{
Log.i(Facebook.LOG_TAG, "LoginListener onFacebookError " + error);
}
You can use one or all of these:
Log.d("tag","string"); :: Debug
Log.v("tag","string"); :: Verbose
Log.e("tag","string"); :: Error
Log.i("tag","string"); :: Info
there are different type of log.
I = Info
V = Verbose
D = Debug
E = Error
Example:
Log.d("tag","the string youd like");
Log.v("tag","the string youd like");
Log.e("tag","the string youd like");
Log.i("tag","the string youd like");
Related
I am learning logging in android code using android studio and emulator
I found that the following command shows a traceback with hyperlink to the code location
Log.d("TAG", "Message with stack trace info", new Throwable());
the image of logcat with hyperlink is
How can i create only the hyperlink part in my log message, without any traceback output
Try this, for example:
import android.util.Log;
public class Logger {
public static void log(String tag, String message) {
String caller = getCallerInfo(new Throwable().getStackTrace());
Log.d(tag, message + caller);
}
private static String getCallerInfo(StackTraceElement[] stacks) {
if (stacks == null || stacks.length < 1) {
return "";
}
StackTraceElement stack = stacks[1];
return String.format(" (%s:%s)", stack.getFileName(), stack.getLineNumber());
}
}
And call it from any where in your code
Logger.log("Manowar", "Today is the good day to die");
As of now the answer by #Cao Mạnh Quang was not giving me the Hyperlink.
The specific String format required for it's generation is this:
return String.format(" %s(%s:%s)", traceE.getClassName(), traceE.getFileName(), traceE.getLineNumber());
which is just the same as:
return stackTraceElement.toString();
so you may as well just do that.
Nothing was working for me...
My guess is that...
This hyperlink is generated by a preconfigured String specification format.
this format follows the className + "(" + fileName + ":" + lineNumber + ")"
If any of those parameters are missing, the hyperlink will not be generated.
There are a couple questions that arise from this:
Is this specification hard coded as a consensus of each LogCat display (IDE side interacts directly with String)
OR
Is this specification hardcoded into the Java code itself? (Java side interprets String generates hyperlink signal + IDE side interprets hyperlink signal and generates it)
The difference between which of these options is the one, would imply whether hyperlink generation is possible simply by changing the required configuration for the Logcat to generate the link either at IDE config level... OR at Java level.
Maybe it is not possible, and this configuration format cannot be changed....
Btw I am sure there must be some super hacky way to achieve this, maybe a way not so intuitive... or maybe it just requires some digging on the IDE config options...
In the android source code i see often line like Slog.v(WindowManagerService.TAG, "First window added to " + this + ", creating SurfaceSession"); How can i see those Slog under android monitor ? And what the difference between Slog and Log?
Short answer
You get logs logged with Slog by default, but they are "hidden" between other log messages. In order to get just the ones logged with Slog use this command:
adb logcat -b system
Long answer
I looked at source of Slog.java:
public static int v(String tag, String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag, msg);
}
Compared to Log.java:
public static int v(String tag, String msg) {
return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
}
As you can see, the difference is solely in LOG_ID parameter.
Then I looked at adb logcat -help:
...
-b <buffer> Request alternate ring buffer, 'main', 'system', 'radio',
'events', 'crash' or 'all'. Multiple -b parameters are
allowed and results are interleaved. The default is
-b main -b system -b crash.
...
I did not check any further - it looks like a safe bet that -b option corresponds to different LOG_ID params.
So I came across something strange that made me loose some time. I have been trying to print the content of an ArrayList containing string elements, sometimes, an element might contain an empty string, which is fine and absolutely my intention.
So I have something like this:
List<String> l = new ArrayList<String>();
//adding strings in l, sometimes it's an empty string
for (int i=0; i < l.size(); i++) {
Log.w("element in l : ", l.get(i));
}
So here, when the loop is gonna hit the empty string, logcat is simply NOT going to print it out BUT (and here is the root of my confusion), if you have a message following the one that failed to display, suddenly the failed message is going to show up as if it contained the new logcat message. For example if you try logging an empty string like this
Log.w(TAG, <empty string here>);
Logcat is going to output nothing at first, then, when it has a NEW message to display this is what it prints out (in this case the new message is some warning about AudioTrack):
08-21 17:06:02.265 13047-13047/company.myapp W/TAG﹕ [ 08-21 17:06:05.411 766: 937 W/AudioTrack ]
AUDIO_OUTPUT_FLAG_FAST denied by client
I'm interested in knowing how this happens, maybe it can help someone else not getting super confused like I did. I suppose trying to log an empty string triggers some kind of buffer that sits there until it gets something to print, is this a bug?
That is an interesting question. I just tried this in LogRabbit and am able to see the same result.
I took a quick browse through the android source and see that Log.W(...) ends up in native code and getting handled in logd_write.c
This basically writes the data to /dev/log/main (or one of the other logs)
You can get those logs like this:
adb pull /dev/log/events .
adb pull /dev/log/main .
adb pull /dev/log/radio .
adb pull /dev/log/system .
You will need to press cntl-C otherwise the copy will happen forever.
Looking in the raw log in /dev/log/main I see the message does get logged:
<8b>F×U^_<8c>^Y^U^Emfl_MessageList^#Before Empty^#^R^#^#^#!z^#^#!z^#^#
<8b>F×U^_<8c>^Y^U^Emfl_MessageList^#^#^]^#^#^#!z^#^#!z^#^#
<8b>F×U^_ <8c>^Y^U^Emfl_MessageList^#After Empty^#7^#^#^#^#^E^#^#^Z^E^#^#
That gets decoded by struct found in logger.h So I think this is a problem in adb. pull the source code from here: (looks like quite a few of undocumented commands there)
This is the primary function
static int logcat(TransportType transport, const char* serial, int argc, const char** argv) {
char* log_tags = getenv("ANDROID_LOG_TAGS");
std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags);
std::string cmd = "shell:export ANDROID_LOG_TAGS=\"" + quoted + "\"; exec logcat";
if (!strcmp(argv[0], "longcat")) {
cmd += " -v long";
}
--argc;
++argv;
while (argc-- > 0) {
cmd += " " + escape_arg(*argv++);
}
return send_shell_command(transport, serial, cmd);
}
Looking in there I see that all logcat does is basically this:
adb shell
> exec logcat
So I think the root of the problem is in logcat itself. Logcat.cpp calls into log_read.c
Based on my quick read through things what I think is happening is the message is not terminated properly. The empty message does not show up until another message is appended and the first message overruns and shows the second message because it has the appropriate termination.
I am trying to make GCM push notifications work in my app and therefore I am using this project (https://github.com/marknutter/GCM-Cordova) as an example.
When I run the example code everything works fine, but when I transfer all the required files and edit my code to let it work in my own app it does not work anymore.
I also tried the following plugin (https://github.com/phonegap-build/PushPlugin) and after installing it automatically it gives exactly the same error.
The app does not crash, but when I call the register function my callback function "onNotificationGCM" does not receive any messages back.
Register function:
window.plugins.GCM.register("my_gcm_id", "onNotificationGCM", successHandler, errorHandler );
After some debugging I figured out that the native android code is able to register the phone and does indeed get an ID message from the GCM server, but that it is unable to send this to my javascript.
Native android code:
public static void sendJavascript( JSONObject _json )
{
String _d = "javascript:"+gECB+"(" + _json.toString() + ")";
Log.v(ME + ":sendJavascript", _d);
if (gECB != null ) {
gwebView.sendJavascript( _d );
}
}
LogCat gives the following 'failed' message:
03-24 17:05:21.844: V/GCMPlugin:sendJavascript(31782): javascript:onNotificationGCM({"regid":"APA91bHX...31ASD","event":"registered"})
03-24 17:05:22.834: D/CordovaLog(31782): processMessage failed: Message: Jjavascript:onNotificationGCM({"regid":"APA91bHX...31ASD","event":"registered"})
The capital J in front of the message is strange and maybe that is what causes the problem, but it seems to be happening somewhere in the Cordova 2.5.0 code.
Does anyone have any idea how I can solve this?
Try to add
window.onNotificationGCM = onNotificationGCM;
to change the context of your function
It solve the problem for me
I had the same problem. After some debugging as I understood I had an unwanted new line character "\n" at the end of my string that I wasn't responsible for and it seems that phone gap added the character. So what I did was to .replace("\n", "") the string on the Java part of the code.
String js = "javascript:displayTextMessage('" + date.toString() + " - " + msg.replace("\n", "") + "');" ;
sendJavascript(js);
This is not an Cordova 2.5.0 Bug! If you copy and paste from the "CORDOVA_GCM_script.js" example, you will have something like this:
case 'registered':
// the definition of the e variable is json return defined in GCMReceiver.java
// In my case on registered I have EVENT and REGID defined
gApp.gcmregid = e.regid;
if ( gApp.gcmregid.length > 0 )
{
$("#app-status-ul").append('<li>REGISTERED -> REGID:' + e.regid + "</li>");
// ==============================================================================
// ==============================================================================
// ==============================================================================
//
// This is where you would code to send the REGID to your server for this device
//
// ==============================================================================
// ==============================================================================
// ==============================================================================
}
break
Make sure the "gApp" Array and the "gcmregedit" variable is declared in your script, or just don't use them in your eventhandler. Otherwise you'll get an "processMessage failed"-Message because of the "undefined"-error occuring before.
Check your code for any incorrect JSON.parse's... these "illegal access" etc. error messages seem to be thrown when JSON.parse(not_a_json_string) happens.
I want to achieve the following but so far, no luck
Open a file in the SD Card when the android application first started.
Stream the logcat output to the file.
When the application exits, stop the logcat streaming.
In my ApplicationClass extends Application onCreate() method, I do this
wwLogManager.openLogFile();
and here's the code in the openLogFile()
private static final String LOGCAT_COMMAND = "logcat -v time -f ";
String timestamp = Long.toString(System.currentTimeMillis());
String logFileName = BuildConstants.LOG_LOCATION + "_" + timestamp + ".log";
mLogFile = new File(Environment.getExternalStorageDirectory() + logFileName);
mLogFile.createNewFile();
String cmd = LOGCAT_COMMAND + mLogFile.getAbsolutePath();
Runtime.getRuntime().exec(cmd);
I do get log files in the sd card, but the log output in these files do not have any trace of the Log.i() calls that I placed in my activities. Is the logcat command that I used here correct? Thanks!
I apologize if I am misunderstanding your goals, but perhaps you could use the java.util.logging API instead of using Logcat or the Android Logging mechanism.
Like the Android logging API, the java.util.logging API allows you to easily log messages at various levels, such as FINE, FINER, WARN, SEVERE, etc.
But the standard logging API has additional advantages, too. For example, you can easily create a log file by using a FileHandler. In fact, FileHandler has a built-in log rotation mechanism, so you don't have to worry (so much) about cleaning up the log files. You can also create a hierarchy of Loggers; so, for example, if you have two Loggers, com.example.foo and com.example.foo.bar, changing the logging level of the former will also change the logging level of the latter. This will even work if the two Loggers are created in different classes! Moreover, you change logging behavior at runtime by specifying a logging configuration file. Finally, you can customize the format of the log by implementing your own Formatter (or just use the SimpleFormatter to avoid the default XML format).
To use the standard logging API, you might try something like this:
// Logger logger is an instance variable
// FileHandler logHandler is an instance variable
try {
String logDirectory =
Environment.getExternalStorageDirectory() + "/log_directory";
// the %g is the number of the current log in the rotation
String logFileName = logDirectory + "/logfile_base_name_%g.log";
// ...
// make sure that the log directory exists, or the next command will fail
//
// create a log file at the specified location that is capped 100kB. Keep up to 5 logs.
logHandler = new FileHandler(logFileName, 100 * 1024, 5);
// use a text-based format instead of the default XML-based format
logHandler.setFormatter(new SimpleFormatter());
// get the actual Logger
logger = Logger.getLogger("com.example.foo");
// Log to the file by associating the FileHandler with the log
logger.addHandler(logHandler);
}
catch (IOException ioe) {
// do something wise
}
// examples of using the logger
logger.finest("This message is only logged at the finest level (lowest/most-verbose level)");
logger.config("This is an config-level message (middle level)");
logger.severe("This is a severe-level message (highest/least-verbose level)");
The Android logging mechanism is certainly easy and convenient. It isn't very customizable, though, and log filtering must be done with tags, which can easily become unwieldy. By using the java.uitl.logging API, you can avoid dealing with a multitude of tags, yet easily limit the log file to specific parts of your application, gain greater control over the location and appearance of the log, and even customize logging behavior at runtime.
I repost my answer here so #JPM and others can see... The code basically just execute the logcat command and then build the log from the input stream.
final StringBuilder log = new StringBuilder();
try {
ArrayList<String> commandLine = new ArrayList<String>();
commandLine.add("logcat");
commandLine.add("-d");
ArrayList<String> arguments = ((params != null) && (params.length > 0)) ? params[0] : null;
if (null != arguments){
commandLine.addAll(arguments);
}
Process process = Runtime.getRuntime().exec(commandLine.toArray(new String[0]));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null){
log.append(line);
log.append(LINE_SEPARATOR);
}
}
catch (IOException e){
//
}
return log;
Try manually setting a filter as described here:
http://developer.android.com/guide/developing/debugging/debugging-log.html#filteringOutput
Something like:
logcat ActivityManager:I MyApp:V *:S
If you replace "MyApp" with the log tags that you are using, that should show you all info (and greater) logs from ActivityManager, and all verbose (and greater) logs from your app.
I know this is a late answer to the question but I would highly recommend using Logback to write messages to a log file as well as the logcat.
Copy logback-android-1.0.10-2.jar and slf4j-api-1.7.5.jar to your libs folder.
Right-Click on both libs and from the menu select Build Path -> Add to Build Path.
Create a logback.xml file in your assets folder and enter the following:
%msg
WARN
${LOG_DIR}/log.txt
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
To write a log:
public class MyActivity extends Activity
{
public static final Logger logger = LoggerFactory.getLogger(MyActivity.class);
protected void onCreate(Bundle b)
{
super(b);
try{
throw new Exception("Test");
}catch(Exception e){
logger.error("Something bad happened",e);
}
}
}