Please tell me that how can I write my own created logs to text file in device ?
I found this code in stackoverflow itself but this code it prints whole logcat, How can I filter the same?
public static void write() {
try {
Process process = Runtime.getRuntime().exec("logcat -d");
// Log.e("","******************---1");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
log = new StringBuilder();
String line;
// Log.e("","******************---2");
while ((line = bufferedReader.readLine()) != null) {
log.append(line);
}
} catch (IOException exception) {
}
//convert log to string
final String logString = new String(log.toString());
//create text file in SDCard
File sdCard = Environment.getExternalStorageDirectory();
// Log.e("","******************---3");
File dir = new File(sdCard.getAbsolutePath() + "/myLogcat");
dir.mkdirs();
File file = new File(dir, "logcat.txt");
try {
//to write logcat in text file
FileOutputStream fOut = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fOut);
// Write the string to the file
osw.write(logString);
// Log.e("", "******************---4");
osw.flush();
osw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Try this :
try {
Process process = Runtime.getRuntime().exec("logcat -d");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
StringBuilder log=new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
log.append(line);
}
appendLog(log.toString());
} catch (IOException e) {
}
Method to write log to file:
public void appendLog(String text) {
File logFile = new File("sdcard/Log.txt");
if (!logFile.exists()) {
try {
logFile.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
// BufferedWriter for performance, true to set append to file flag
BufferedWriter buf = new BufferedWriter(new FileWriter(logFile,
true));
buf.append(text);
buf.newLine();
buf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Add the following permission in manifest file also :
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
First check out the log locations here: https://android.stackexchange.com/questions/14430/how-can-i-view-and-examine-the-android-log
If that's not good enough, you can always make your own Log.java class which would log directly to the file you want (though you should really reconsider using LogCat as it is working as expected).
As a alternate way you can create your custom logger.
Here is one sample util class that I have created for my project.
import android.os.Environment;
import android.util.Log;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
/**
* TODO: Add a class header comment!
*
* #author Dhaval Patel
* #version 1.0, May 24, 2015
* #since 1.0
*/
public final class Logger {
public static final int MAX_FILE_SIZE = 1024*1024*5;// max file size 5MB, if file size increase, Logger will create new file.
private static final String LOG_PREFIX = "prefix_";
private static final int LOG_PREFIX_LENGTH = LOG_PREFIX.length();
private static final int MAX_LOG_TAG_LENGTH = 23;
private static final Boolean ENABLE_CONSOLE_LOG = true; //Flag to enable or disable console log
private static final Boolean ENABLE_FILE_LOG = true; //Flag to enable or disable file log
private static final LogLevel GLOBAL_LOG_LEVEL = LogLevel.VERBOSE; //Flag indicate log level
private static final String LOG_DIRECTORY = Environment.getExternalStorageDirectory()+"log"+File.separator; //Log directory
public static String makeLogTag(String str) {
if (str.length() > MAX_LOG_TAG_LENGTH - LOG_PREFIX_LENGTH) {
return LOG_PREFIX + str.substring(0, MAX_LOG_TAG_LENGTH - LOG_PREFIX_LENGTH - 1);
}
return LOG_PREFIX + str;
}
private enum LogLevel{
VERBOSE(Log.VERBOSE),
DEBUG(Log.DEBUG),
INFO(Log.INFO),
WARNING(Log.WARN),
ERROR(Log.ERROR),
ASSERT(Log.ASSERT);
private final int logLevel;
LogLevel(int logLevel) {
this.logLevel = logLevel;
}
public int getLogLevel() {
return logLevel;
}
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
*
*/
public static void v(String tag, String msg) {
write(LogLevel.VERBOSE, tag, msg);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
* #param tr An exception to log
*
*/
public static void v(String tag, String msg, Throwable tr) {
write(LogLevel.VERBOSE, tag, msg, tr);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
*
*/
public static void d(String tag, String msg) {
write(LogLevel.DEBUG, tag, msg);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
* #param tr An exception to log
*
*/
public static void d(String tag, String msg, Throwable tr) {
write(LogLevel.DEBUG, tag, msg, tr);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
*
*/
public static void i(String tag, String msg) {
write(LogLevel.INFO, tag, msg);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
* #param tr An exception to log
*
*/
public static void i(String tag, String msg, Throwable tr) {
write(LogLevel.INFO, tag, msg, tr);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
*
*/
public static void w(String tag, String msg) {
write(LogLevel.WARNING, tag, msg);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
* #param tr An exception to log
*
*/
public static void w(String tag, String msg, Throwable tr) {
write(LogLevel.WARNING, tag, msg, tr);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
*
*/
public static void e(String tag, String msg) {
write(LogLevel.ERROR, tag, msg);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
* #param tr An exception to log
*
*/
public static void e(String tag, String msg, Throwable tr) {
write(LogLevel.ERROR, tag, msg, tr);
}
private static boolean isLogEnable(LogLevel logLevel){
return GLOBAL_LOG_LEVEL.getLogLevel() <= logLevel.getLogLevel();
}
private static void write(LogLevel logLevel, String tag, String log) {
if (isLogEnable(logLevel) && ENABLE_FILE_LOG){
StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[4];
String logPoint = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
String msg = "["+getCurrentDateTime()+"] "+ logLevel.name() +" "+ logPoint +" "+tag+"//:"+log;
write(msg);
}
if (isLogEnable(logLevel) && ENABLE_CONSOLE_LOG){
Log.println(logLevel.getLogLevel(), makeLogTag(tag), log);
}
}
private static void write(LogLevel logLevel, String tag, String log, Throwable tr){
if (isLogEnable(logLevel) && ENABLE_FILE_LOG){
StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[4];
String logPoint = stackTraceElement.getClassName() + "::" + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
String msg = "["+getCurrentDateTime()+"] "+ logLevel.name() +" "+ logPoint+" "+tag+"//:"+log+"\n"+Log.getStackTraceString(tr);
write(msg);
}
if (isLogEnable(logLevel) && ENABLE_CONSOLE_LOG){
Log.println(logLevel.getLogLevel(), makeLogTag(tag), log + "\n" + Log.getStackTraceString(tr));
}
}
private static void write(String text){
BufferedWriter out = null;
String filePath=LOG_DIRECTORY;
try {
SimpleDateFormat df = new SimpleDateFormat("dd_MMM_yyyy", Locale.ENGLISH);
String formattedDate = df.format(System.currentTimeMillis());
if(!new File(LOG_DIRECTORY).exists()) {
new File(LOG_DIRECTORY).mkdirs();
}
filePath = LOG_DIRECTORY +formattedDate+".log";
while (new File(filePath).exists() && new File(filePath).length() > MAX_FILE_SIZE) {
String[] txt1 = filePath.split("\\.log");
int fileNum = 1;
if (txt1.length == 2) {
fileNum = Integer.parseInt(txt1[1].substring(1));
fileNum++;
}
filePath = LOG_DIRECTORY + formattedDate + ".log" + "." + fileNum;
}
if(!new File(filePath).exists()){
new File(filePath).createNewFile();
}
if(new File(filePath).exists()){
FileWriter fStream = new FileWriter(filePath, true);
out = new BufferedWriter(fStream);
out.write(text + "\n" + new File(filePath).length());
out.flush();
}
} catch (IOException e) {
Log.e("Log", "Path:"+filePath);
e.printStackTrace();
} catch (Exception e) {
Log.e("Log", e.getMessage());
e.printStackTrace();
} finally {
try {
if(out!=null)
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static String getCurrentDateTime(){
return new SimpleDateFormat("dd MMM yyyy HH:mm:ss:SSS" , Locale.getDefault()).format(Calendar.getInstance().getTime());
}
}
Use it same like your android Log.
Logger.i("Info", "my sample log");
Here log store in file date-wise, you can modify write method as per your needs.
Related
"android.os.SystemProperties" is cannot be used from outside so reflection is used for a set and get operations
#see Where is android.os.SystemProperties?
/**
* Sets the value for the given key.
*
* #throws IllegalArgumentException if the key exceeds 32 characters
* #throws IllegalArgumentException if the value exceeds 92 characters
*/
private static void setProperty(String key, String val) throws IllegalArgumentException {
try {
Class<?> sysProps = Class.forName("android.os.SystemProperties");
#SuppressWarnings("rawtypes")
final Class[] argsTypes = { String.class, String.class };
final Method setter = sysProps.getMethod("set", argsTypes);
final Object[] params = { key, val };
setter.invoke(sysProps, params);
} catch (IllegalArgumentException iaex) {
System.out.println("IllegalArgumentException :"+ iaex.getMessage());
throw iaex;
} catch (Exception ex) {
System.out.println("Exception :"+ ex.getMessage());
}
}
/**
* Get the value for the given key.
*
* #return An empty string if the key is not found
* #throws IllegalArgumentException if the key length exceeds 32 characters
*/
public static String getProperty(String key) throws IllegalArgumentException {
String value;
try {
Class<?> sysProps = Class.forName("android.os.SystemProperties");
#SuppressWarnings("rawtypes")
final Class[] argTypes = { String.class };
final Method getter = sysProps.getMethod("get", argTypes);
final Object[] params = { key };
value = getter.invoke(sysProps, params).toString();
} catch (IllegalArgumentException iaex) {
System.out.println("IllegalArgumentException :"+ iaex.getMessage());
throw iaex;
} catch (Exception ex) {
System.out.println("Exception :"+ ex.getMessage());
value = "";
}
return value;
}
my test function from a target application
public class A {
public static boolean isDone() { return "V1".equals(SystemProperties.get("K1")); }
}
Then I wrote a following test method
#Test
public void Should_return_truth_isDone() {
try (MockedStatic<A> mocked = mockStatic(A.class)) {
setProperty("K1", "V1");
mocked
.when(() -> A.isDone())
.thenCallRealMethod();
System.out.println(" K1:"+ getProperty("K1"));
System.out.println(" isDone:"+ (A.isDone() ? "O" : "X"));
assertTrue(A.isDone());
}
}
Issue is it's always failing and log shows values are empty - which means values are not saved.
Exception :android.os.SystemProperties
K1:
isDone:X
I am trying to connect to Firebase Cloud Messaging by using smack library.
I don't have much knowledge of the Smack API. After reading the Firebase docs, I see that the connection must be authenticated and there are a series of responses back and forth between "app server" and Cloud Connection Servers. According to the docs, I must create a Sasl Plain authentication. I don't know how to implement this. But after reading some posts by other StackOverFlow users I see that I must create an authentication class. Specifically, I was reviewing the answers and comments on "Gtalk XMPP SASL authentication failed using mechanism X-OAUTH2?" These responses that are between CCS and the "app server" are enclosed in and tags. I dont know how to use Smack to get or build these responses. I do have my connection set up with XMPP, and I've tried setting a addAsyncStanzListener to my XMPP connection with the hopes of getting some of these responses from CCS. But, nothing comes in. The responses between "app server" and CCS could be found in this link https://firebase.google.com/docs/cloud-messaging/server#connecting
Does anyone here know how to proceed from here. I think that Smack is not well documented and having little knowledge of XMPP makes it even worse. There are all these classes, Packets, extensions, IQ class, XML pull parsers etc.
Any rough structure on the set up would be ideal.
Thanks
Here is a snippet of my server code that I use with Firebase. If you want to understand in more detail try this blog post (it is how I figured out how to get everything to work in the end): http://www.grokkingandroid.com/xmpp-server-google-cloud-messaging/
In order to get the code below to work you will need to go to the Firebase console and go to project settings
From here you will need to take note of your Server Key and Sender ID and replace it in the code snippet below (it is near the bottom of the code) and save it in your path as SmackCcsClient.class
After doing that you can compile and run your server through the command promt:
// Set up java file (replace PATH_TO_WHERE_YOUR_CLASS_IS with your own path and make sure to put the json and smack JARs there as well
javac -d PATH_TO_WHERE_YOUR_CLASS_IS -sourcepath src -cp PATH_TO_WHERE_YOUR_CLASS_IS\json-simple-1.1.1.jar;PATH_TO_WHERE_YOUR_CLASS_IS\smack-3.4.1-0cec571.jar PATH_TO_WHERE_YOUR_CLASS_IS\SmackCcsClient.java
// Run
java -cp PATH_TO_WHERE_YOUR_CLASS_IS;PATH_TO_WHERE_YOUR_CLASS_IS\json-simple-1.1.1.jar;PATH_TO_WHERE_YOUR_CLASS_IS\smack-3.4.1-0cec571.jar SmackCcsClient
/*
SmackCcsClient:
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.PacketInterceptor;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.DefaultPacketExtension;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.util.StringUtils;
import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;
import org.xmlpull.v1.XmlPullParser;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.*;
import javax.net.ssl.SSLSocketFactory;
/**
* Sample Smack implementation of a client for GCM Cloud Connection Server.
*
* For illustration purposes only.
*/
public class SmackCcsClient {
static final String REG_ID_STORE = "gcmchat.txt";
static final String MESSAGE_KEY = "SM";
Logger logger = Logger.getLogger("SmackCcsClient");
public static final String GCM_SERVER = "fcm-xmpp.googleapis.com";
public static final int GCM_PORT = 5235;
public static final String GCM_ELEMENT_NAME = "gcm";
public static final String GCM_NAMESPACE = "google:mobile:data";
static Random random = new Random();
XMPPConnection connection;
ConnectionConfiguration config;
/**
* XMPP Packet Extension for GCM Cloud Connection Server.
*/
class GcmPacketExtension extends DefaultPacketExtension {
String json;
public GcmPacketExtension(String json) {
super(GCM_ELEMENT_NAME, GCM_NAMESPACE);
this.json = json;
}
public String getJson() {
return json;
}
#Override
public String toXML() {
return String.format("<%s xmlns=\"%s\">%s</%s>", GCM_ELEMENT_NAME,
GCM_NAMESPACE, json, GCM_ELEMENT_NAME);
}
#SuppressWarnings("unused")
public Packet toPacket() {
return new Message() {
// Must override toXML() because it includes a <body>
#Override
public String toXML() {
StringBuilder buf = new StringBuilder();
buf.append("<message");
if (getXmlns() != null) {
buf.append(" xmlns=\"").append(getXmlns()).append("\"");
}
if (getLanguage() != null) {
buf.append(" xml:lang=\"").append(getLanguage())
.append("\"");
}
if (getPacketID() != null) {
buf.append(" id=\"").append(getPacketID()).append("\"");
}
if (getTo() != null) {
buf.append(" to=\"")
.append(StringUtils.escapeForXML(getTo()))
.append("\"");
}
if (getFrom() != null) {
buf.append(" from=\"")
.append(StringUtils.escapeForXML(getFrom()))
.append("\"");
}
buf.append(">");
buf.append(GcmPacketExtension.this.toXML());
buf.append("</message>");
return buf.toString();
}
};
}
}
public SmackCcsClient() {
// Add GcmPacketExtension
ProviderManager.getInstance().addExtensionProvider(GCM_ELEMENT_NAME,
GCM_NAMESPACE, new PacketExtensionProvider() {
#Override
public PacketExtension parseExtension(XmlPullParser parser)
throws Exception {
String json = parser.nextText();
GcmPacketExtension packet = new GcmPacketExtension(json);
return packet;
}
});
}
/**
* Returns a random message id to uniquely identify a message.
*
* <p>
* Note: This is generated by a pseudo random number generator for
* illustration purpose, and is not guaranteed to be unique.
*
*/
public String getRandomMessageId() {
return "m-" + Long.toString(random.nextLong());
}
/**
* Sends a downstream GCM message.
*/
public void send(String jsonRequest) {
Packet request = new GcmPacketExtension(jsonRequest).toPacket();
connection.sendPacket(request);
}
/**
* Handles an upstream data message from a device application.
*
* <p>
* This sample echo server sends an echo message back to the device.
* Subclasses should override this method to process an upstream message.
*/
public void handleIncomingDataMessage(Map<String, Object> jsonObject) {
String from = jsonObject.get("from").toString();
// PackageName of the application that sent this message.
String category = jsonObject.get("category").toString();
// Use the packageName as the collapseKey in the echo packet
String collapseKey = "echo:CollapseKey";
#SuppressWarnings("unchecked")
Map<String, String> payload = (Map<String, String>) jsonObject
.get("data");
String messageText = payload.get("message_text");
String messageFrom = payload.get("message_userfrom");
String messageTime = payload.get("message_timestamp");
String toUser = payload.get("message_recipient");
payload.put("message_text", messageText);
payload.put("message_userfrom", messageFrom);
payload.put("message_timestamp", messageTime);
String message = createJsonMessage(toUser, getRandomMessageId(),
payload, collapseKey, null, false);
send(message);
}
/**
* Handles an ACK.
*
* <p>
* By default, it only logs a INFO message, but subclasses could override it
* to properly handle ACKS.
*/
public void handleAckReceipt(Map<String, Object> jsonObject) {
String messageId = jsonObject.get("message_id").toString();
String from = jsonObject.get("from").toString();
logger.log(Level.INFO, "handleAckReceipt() from: " + from
+ ", messageId: " + messageId);
}
/**
* Handles a NACK.
*
* <p>
* By default, it only logs a INFO message, but subclasses could override it
* to properly handle NACKS.
*/
public void handleNackReceipt(Map<String, Object> jsonObject) {
String messageId = jsonObject.get("message_id").toString();
String from = jsonObject.get("from").toString();
logger.log(Level.INFO, "handleNackReceipt() from: " + from
+ ", messageId: " + messageId);
}
/**
* Creates a JSON encoded GCM message.
*
* #param to
* RegistrationId of the target device (Required).
* #param messageId
* Unique messageId for which CCS will send an "ack/nack"
* (Required).
* #param payload
* Message content intended for the application. (Optional).
* #param collapseKey
* GCM collapse_key parameter (Optional).
* #param timeToLive
* GCM time_to_live parameter (Optional).
* #param delayWhileIdle
* GCM delay_while_idle parameter (Optional).
* #return JSON encoded GCM message.
*/
public static String createJsonMessage(String to, String messageId,
Map<String, String> payload, String collapseKey, Long timeToLive,
Boolean delayWhileIdle) {
Map<String, Object> message = new HashMap<String, Object>();
message.put("to", to);
if (collapseKey != null) {
message.put("collapse_key", collapseKey);
}
if (timeToLive != null) {
message.put("time_to_live", timeToLive);
}
if (delayWhileIdle != null && delayWhileIdle) {
message.put("delay_while_idle", true);
}
message.put("message_id", messageId);
message.put("data", payload);
return JSONValue.toJSONString(message);
}
/**
* Creates a JSON encoded ACK message for an upstream message received from
* an application.
*
* #param to
* RegistrationId of the device who sent the upstream message.
* #param messageId
* messageId of the upstream message to be acknowledged to CCS.
* #return JSON encoded ack.
*/
public static String createJsonAck(String to, String messageId) {
Map<String, Object> message = new HashMap<String, Object>();
message.put("message_type", "ack");
message.put("to", to);
message.put("message_id", messageId);
return JSONValue.toJSONString(message);
}
/**
* Connects to GCM Cloud Connection Server using the supplied credentials.
*
* #param username
* GCM_SENDER_ID#gcm.googleapis.com
* #param password
* API Key
* #throws XMPPException
*/
public void connect(String username, String password) throws XMPPException {
config = new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
config.setSecurityMode(SecurityMode.enabled);
config.setReconnectionAllowed(true);
config.setRosterLoadedAtLogin(false);
config.setSendPresence(false);
config.setSocketFactory(SSLSocketFactory.getDefault());
// NOTE: Set to true to launch a window with information about packets
// sent and received
config.setDebuggerEnabled(true);
// -Dsmack.debugEnabled=true
XMPPConnection.DEBUG_ENABLED = true;
connection = new XMPPConnection(config);
connection.connect();
connection.addConnectionListener(new ConnectionListener() {
#Override
public void reconnectionSuccessful() {
logger.info("Reconnecting..");
}
#Override
public void reconnectionFailed(Exception e) {
logger.log(Level.INFO, "Reconnection failed.. ", e);
}
#Override
public void reconnectingIn(int seconds) {
logger.log(Level.INFO, "Reconnecting in %d secs", seconds);
}
#Override
public void connectionClosedOnError(Exception e) {
logger.log(Level.INFO, "Connection closed on error.");
}
#Override
public void connectionClosed() {
logger.info("Connection closed.");
}
});
// Handle incoming packets
connection.addPacketListener(new PacketListener() {
#Override
public void processPacket(Packet packet) {
logger.log(Level.INFO, "Received: " + packet.toXML());
Message incomingMessage = (Message) packet;
GcmPacketExtension gcmPacket = (GcmPacketExtension) incomingMessage
.getExtension(GCM_NAMESPACE);
String json = gcmPacket.getJson();
try {
#SuppressWarnings("unchecked")
Map<String, Object> jsonObject = (Map<String, Object>) JSONValue
.parseWithException(json);
// present for "ack"/"nack", null otherwise
Object messageType = jsonObject.get("message_type");
if (messageType == null) {
// Normal upstream data message
handleIncomingDataMessage(jsonObject);
// Send ACK to CCS
String messageId = jsonObject.get("message_id")
.toString();
String from = jsonObject.get("from").toString();
String ack = createJsonAck(from, messageId);
send(ack);
} else if ("ack".equals(messageType.toString())) {
// Process Ack
handleAckReceipt(jsonObject);
} else if ("nack".equals(messageType.toString())) {
// Process Nack
handleNackReceipt(jsonObject);
} else {
logger.log(Level.WARNING,
"Unrecognized message type (%s)",
messageType.toString());
}
} catch (ParseException e) {
logger.log(Level.SEVERE, "Error parsing JSON " + json, e);
} catch (Exception e) {
logger.log(Level.SEVERE, "Couldn't send echo.", e);
}
}
}, new PacketTypeFilter(Message.class));
// Log all outgoing packets
connection.addPacketInterceptor(new PacketInterceptor() {
#Override
public void interceptPacket(Packet packet) {
logger.log(Level.INFO, "Sent: {0}", packet.toXML());
}
}, new PacketTypeFilter(Message.class));
connection.login(username, password);
}
public void writeToFile(String name, String regId) throws IOException {
Map<String, String> regIdMap = readFromFile();
regIdMap.put(name, regId);
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(
REG_ID_STORE, false)));
for (Map.Entry<String, String> entry : regIdMap.entrySet()) {
out.println(entry.getKey() + "," + entry.getValue());
}
out.println(name + "," + regId);
out.close();
}
public Map<String, String> readFromFile() {
Map<String, String> regIdMap = null;
try {
BufferedReader br = new BufferedReader(new FileReader(REG_ID_STORE));
String regIdLine = "";
regIdMap = new HashMap<String, String>();
while ((regIdLine = br.readLine()) != null) {
String[] regArr = regIdLine.split(",");
regIdMap.put(regArr[0], regArr[1]);
}
br.close();
} catch(IOException ioe) {
}
return regIdMap;
}
public static void main(String [] args) {
final String userName = "Sender ID" + "#gcm.googleapis.com";
final String password = "Server key";
SmackCcsClient ccsClient = new SmackCcsClient();
try {
ccsClient.connect(userName, password);
} catch (XMPPException e) {
e.printStackTrace();
}
}
}
This question already has answers here:
android logcat logs chatty module line expire message
(5 answers)
Closed 6 years ago.
So I'm trying to find an elusive bug in a large codebase. As such, I've put a lot of logging into my app. I'm lucky enough to have multiple testers working on this. However, I've found that a lot of my logcat logs are missing. They're hidden as 'chatty'. For example
1799 12017 I logd: uid=10007 chatty comm=Binder_B, expire 4 lines
I've found some mention of using the adb command
adb logcat -p
but I can't find any documentation for the -p. I've also found that with a lot of devices (possibly all devices on Marshmallow) this is not supported.
Other than having the device plugged into Android Studio / Eclipse, is there a way to stop 'chatty' from hiding my logs?
I also can't find documentation, but according to Issue 202457 - android - Disable chatty filtering of log messages (I/chatty ... expire N lines) - Android Open Source Project - Issue Tracker the command you want is
adb logcat -P ""
I've created my own debugger and DEBUG_MODE & DEBUG_WITH_STACKTRACE_MODE
are enabled true in build.gradle debug{} and false bydefault
public class AppLoger {
public static boolean DEBUG_MODE = BuildConfig.LOG_DEBUG_MODE;
public static boolean DEBUG_WITH_STACKTRACE_MODE = BuildConfig.LOG_DEBUG_WITH_STACKTRACE_MODE;
/**
* #param cls Class<T>
* #param message String
* #author Android Lead
*/
public static <T> void logInfo(Class<T> cls, String message) {
if (DEBUG_MODE || DEBUG_WITH_STACKTRACE_MODE) {
String tag = cls.getName();
Log.i(tag, "-----");
Log.i(tag, LogType.INFO + ": " + message);
if (DEBUG_WITH_STACKTRACE_MODE) {
Log.i(tag, getStackTrace());
}
}
}
/**
* #param cls Class<T>
* #param message String
* #author Android Lead
*/
public static <T> void logWarning(Class<T> cls, String message) {
if (DEBUG_MODE || DEBUG_WITH_STACKTRACE_MODE) {
String tag = cls.getName();
Log.w(tag, "-----");
Log.w(tag, LogType.WARNING + ": " + message);
if (DEBUG_WITH_STACKTRACE_MODE) {
Log.w(tag, getStackTrace());
}
}
}
/**
* #param cls Class<T>
* #param message String
* #author Android Lead
*/
public static <T> void logError(Class<T> cls, String message) {
if (DEBUG_MODE || DEBUG_WITH_STACKTRACE_MODE) {
String tag = cls.getName();
Log.e(tag, "-----");
Log.e(tag, LogType.ERROR + ": " + message);
if (DEBUG_WITH_STACKTRACE_MODE) {
Log.e(tag, getStackTrace());
}
}
}
/**
* #param cls Class<T>
* #param message String
* #author Android Lead
*/
public static <T> void logError(Class<T> cls, String message, Throwable e) {
if (DEBUG_MODE || DEBUG_WITH_STACKTRACE_MODE) {
String tag = cls.getName();
Log.e(tag, "-----");
Log.e(tag, LogType.ERROR + ": " + message, e);
if (DEBUG_WITH_STACKTRACE_MODE) {
Log.e(tag, getStackTrace());
}
}
}
/**
* #param tag String
* #param msg String/JSON/ArrayList
* #author Android Lead
*/
public static void e(String tag, Object msg) {
if (DEBUG_MODE || DEBUG_WITH_STACKTRACE_MODE)
Log.e(tag, "" + msg);
}
/**
* #param tag String
* #param msg String/JSON/ArrayList
* #author Android Lead
*/
public static void i(String tag, Object msg) {
if (DEBUG_MODE || DEBUG_WITH_STACKTRACE_MODE)
Log.i(tag, "" + msg);
}
/**
* #author Android Lead
*/
private static String getStackTrace() {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
new Throwable().printStackTrace(pw);
return sw.toString();
}
private enum LogType {
INFO, WARNING, ERROR
}
}
In my application I have local service, which needs to be run in separate process. It is specified as
<service android:name=".MyService" android:process=":myservice"></service>
in AndroidManifest.xml. I also subclass Application object and want to detect in it's onCreate method when it is called by ordinary launch and when by myservice launch. The only working solution that I have found is described by
https://stackoverflow.com/a/28907058/2289482
But I don't want to get all running processes on device and iterate over them. I try to use getApplicationInfo().processName from Context, but unfortunately it always return the same String, while the solution in the link above return: myPackage, myPackage:myservice. I don't need processName at the first place, but some good solution to determine when onCreate method is called by ordinary launch and when by myservice launch. May be it can be done by applying some kind of tag or label somewhere, but i didn't find how to do it.
You can use this code to get your process name:
int myPid = android.os.Process.myPid(); // Get my Process ID
InputStreamReader reader = null;
try {
reader = new InputStreamReader(
new FileInputStream("/proc/" + myPid + "/cmdline"));
StringBuilder processName = new StringBuilder();
int c;
while ((c = reader.read()) > 0) {
processName.append((char) c);
}
// processName.toString() is my process name!
Log.v("XXX", "My process name is: " + processName.toString());
} catch (Exception e) {
// ignore
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e) {
// Ignore
}
}
}
From Acra sources. The same way as above answer but presents useful methods
private static final String ACRA_PRIVATE_PROCESS_NAME= ":acra";
/**
* #return true if the current process is the process running the SenderService.
* NB this assumes that your SenderService is configured to used the default ':acra' process.
*/
public static boolean isACRASenderServiceProcess() {
final String processName = getCurrentProcessName();
if (ACRA.DEV_LOGGING) log.d(LOG_TAG, "ACRA processName='" + processName + '\'');
//processName sometimes (or always?) starts with the package name, so we use endsWith instead of equals
return processName != null && processName.endsWith(ACRA_PRIVATE_PROCESS_NAME);
}
#Nullable
private static String getCurrentProcessName() {
try {
return IOUtils.streamToString(new FileInputStream("/proc/self/cmdline")).trim();
} catch (IOException e) {
return null;
}
}
private static final Predicate<String> DEFAULT_FILTER = new Predicate<String>() {
#Override
public boolean apply(String s) {
return true;
}
};
private static final int NO_LIMIT = -1;
public static final int DEFAULT_BUFFER_SIZE_IN_BYTES = 8192;
/**
* Reads an InputStream into a string
*
* #param input InputStream to read.
* #return the String that was read.
* #throws IOException if the InputStream could not be read.
*/
#NonNull
public static String streamToString(#NonNull InputStream input) throws IOException {
return streamToString(input, DEFAULT_FILTER, NO_LIMIT);
}
/**
* Reads an InputStream into a string
*
* #param input InputStream to read.
* #param filter Predicate that should return false for lines which should be excluded.
* #param limit the maximum number of lines to read (the last x lines are kept)
* #return the String that was read.
* #throws IOException if the InputStream could not be read.
*/
#NonNull
public static String streamToString(#NonNull InputStream input, Predicate<String> filter, int limit) throws IOException {
final BufferedReader reader = new BufferedReader(new InputStreamReader(input), ACRAConstants.DEFAULT_BUFFER_SIZE_IN_BYTES);
try {
String line;
final List<String> buffer = limit == NO_LIMIT ? new LinkedList<String>() : new BoundedLinkedList<String>(limit);
while ((line = reader.readLine()) != null) {
if (filter.apply(line)) {
buffer.add(line);
}
}
return TextUtils.join("\n", buffer);
} finally {
safeClose(reader);
}
}
/**
* Closes a Closeable.
*
* #param closeable Closeable to close. If closeable is null then method just returns.
*/
public static void safeClose(#Nullable Closeable closeable) {
if (closeable == null) return;
try {
closeable.close();
} catch (IOException ignored) {
// We made out best effort to release this resource. Nothing more we can do.
}
}
You can use the next method
#Nullable
public static String getProcessName(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo processInfo : activityManager.getRunningAppProcesses()) {
if (processInfo.pid == android.os.Process.myPid()) {
return processInfo.processName;
}
}
return null;
}
I want to read and react to logcat logs within my application.
I found the following code:
try {
Process process = Runtime.getRuntime().exec("logcat -d");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
StringBuilder log=new StringBuilder();
String line = "";
while ((line = bufferedReader.readLine()) != null) {
log.append(line);
}
TextView tv = (TextView)findViewById(R.id.textView1);
tv.setText(log.toString());
}
catch (IOException e) {}
This code indeed returns the logcat logs that made until the application was started -
But is it possible to continuously listen to even new logcat logs?
You can keep reading the logs, just by removing the "-d" flag in your code above.
The "-d" flag instruct to logcat to show log content and exit. If you remove the flag, logcat will not terminate and keeps sending any new line added to it.
Just have in mind that this may block your application if not correctly designed.
good luck.
With coroutines and the official lifecycle-livedata-ktx and lifecycle-viewmodel-ktx libraries it's simple like that:
class LogCatViewModel : ViewModel() {
fun logCatOutput() = liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
Runtime.getRuntime().exec("logcat -c")
Runtime.getRuntime().exec("logcat")
.inputStream
.bufferedReader()
.useLines { lines -> lines.forEach { line -> emit(line) }
}
}
}
Usage
val logCatViewModel by viewModels<LogCatViewModel>()
logCatViewModel.logCatOutput().observe(this, Observer{ logMessage ->
logMessageTextView.append("$logMessage\n")
})
You can clear your logcat with this method i'm using to clear after writing logcat to a file to avoid duplicated lines:
public void clearLog(){
try {
Process process = new ProcessBuilder()
.command("logcat", "-c")
.redirectErrorStream(true)
.start();
} catch (IOException e) {
}
}
Here is a quick put-together/drop-in that can be used for capturing all current, or all new (since a last request) log items.
You should modify/extend this, because you might want to return a continuous-stream rather than a LogCapture.
The Android LogCat "Manual": https://developer.android.com/studio/command-line/logcat.html
import android.util.Log;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Stack;
/**
* Created by triston on 6/30/17.
*/
public class Logger {
// http://www.java2s.com/Tutorial/Java/0040__Data-Type/SimpleDateFormat.htm
private static final String ANDROID_LOG_TIME_FORMAT = "MM-dd kk:mm:ss.SSS";
private static SimpleDateFormat logCatDate = new SimpleDateFormat(ANDROID_LOG_TIME_FORMAT);
public static String lineEnding = "\n";
private final String logKey;
private static List<String> logKeys = new ArrayList<String>();
Logger(String tag) {
logKey = tag;
if (! logKeys.contains(tag)) logKeys.add(logKey);
}
public static class LogCapture {
private String lastLogTime = null;
public final String buffer;
public final List<String> log, keys;
LogCapture(String oLogBuffer, List<String>oLogKeys) {
this.buffer = oLogBuffer;
this.keys = oLogKeys;
this.log = new ArrayList<>();
}
private void close() {
if (isEmpty()) return;
String[] out = log.get(log.size() - 1).split(" ");
lastLogTime = (out[0]+" "+out[1]);
}
private boolean isEmpty() {
return log.size() == 0;
}
public LogCapture getNextCapture() {
LogCapture capture = getLogCat(buffer, lastLogTime, keys);
if (capture == null || capture.isEmpty()) return null;
return capture;
}
public String toString() {
StringBuilder output = new StringBuilder();
for (String data : log) {
output.append(data+lineEnding);
}
return output.toString();
}
}
/**
* Get a list of the known log keys
* #return copy only
*/
public static List<String> getLogKeys() {
return logKeys.subList(0, logKeys.size() - 1);
}
/**
* Platform: Android
* Get the logcat output in time format from a buffer for this set of static logKeys.
* #param oLogBuffer logcat buffer ring
* #return A log capture which can be used to make further captures.
*/
public static LogCapture getLogCat(String oLogBuffer) { return getLogCat(oLogBuffer, null, getLogKeys()); }
/**
* Platform: Android
* Get the logcat output in time format from a buffer for a set of log-keys; since a specified time.
* #param oLogBuffer logcat buffer ring
* #param oLogTime time at which to start capturing log data, or null for all data
* #param oLogKeys logcat tags to capture
* #return A log capture; which can be used to make further captures.
*/
public static LogCapture getLogCat(String oLogBuffer, String oLogTime, List<String> oLogKeys) {
try {
List<String>sCommand = new ArrayList<String>();
sCommand.add("logcat");
sCommand.add("-bmain");
sCommand.add("-vtime");
sCommand.add("-s");
sCommand.add("-d");
sCommand.add("-T"+oLogTime);
for (String item : oLogKeys) sCommand.add(item+":V"); // log level: ALL
sCommand.add("*:S"); // ignore logs which are not selected
Process process = new ProcessBuilder().command(sCommand).start();
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
LogCapture mLogCapture = new LogCapture(oLogBuffer, oLogKeys);
String line = "";
long lLogTime = logCatDate.parse(oLogTime).getTime();
if (lLogTime > 0) {
// Synchronize with "NO YEAR CLOCK" # unix epoch-year: 1970
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date(oLogTime));
calendar.set(Calendar.YEAR, 1970);
Date calDate = calendar.getTime();
lLogTime = calDate.getTime();
}
while ((line = bufferedReader.readLine()) != null) {
long when = logCatDate.parse(line).getTime();
if (when > lLogTime) {
mLogCapture.log.add(line);
break; // stop checking for date matching
}
}
// continue collecting
while ((line = bufferedReader.readLine()) != null) mLogCapture.log.add(line);
mLogCapture.close();
return mLogCapture;
} catch (Exception e) {
// since this is a log reader, there is nowhere to go and nothing useful to do
return null;
}
}
/**
* "Error"
* #param e
*/
public void failure(Exception e) {
Log.e(logKey, Log.getStackTraceString(e));
}
/**
* "Error"
* #param message
* #param e
*/
public void failure(String message, Exception e) {
Log.e(logKey, message, e);
}
public void warning(String message) {
Log.w(logKey, message);
}
public void warning(String message, Exception e) {
Log.w(logKey, message, e);
}
/**
* "Information"
* #param message
*/
public void message(String message) {
Log.i(logKey, message);
}
/**
* "Debug"
* #param message a Message
*/
public void examination(String message) {
Log.d(logKey, message);
}
/**
* "Debug"
* #param message a Message
* #param e An failure
*/
public void examination(String message, Exception e) {
Log.d(logKey, message, e);
}
}
In your project which performs activity logging:
Logger log = new Logger("SuperLog");
// perform logging methods
When you want to capture everything you logged through "Logger"
LogCapture capture = Logger.getLogCat("main");
When you get hungry and you want to snack on more logs
LogCapture nextCapture = capture.getNextCapture();
You can get the capture as a string with
String captureString = capture.toString();
Or you can get the log items of the capture with
String logItem = capture.log.get(itemNumber);
There is no exact static method to capture foreign log keys but there is a way none the less
LogCapture foreignCapture = Logger.getLogCat("main", null, foreignCaptureKeyList);
Using the above will also permit you to call Logger.this.nextCapture on the foreign capture.
Based on #user1185087's answer, a simple solution without ViewModel could be:
Start the job on an IO thread:
// Custom scope for collecting logs on IO threads.
val scope = CoroutineScope(Job() + Dispatchers.IO)
val job = scope.launch {
Runtime.getRuntime().exec("logcat -c") // Clear logs
Runtime.getRuntime().exec("logcat") // Start to capture new logs
.inputStream
.bufferedReader()
.useLines { lines ->
// Note that this forEach loop is an infinite loop until this job is cancelled.
lines.forEach { newLine ->
// Check whether this job is cancelled, since a coroutine must
// cooperate to be cancellable.
ensureActive()
// TODO: Write newLine into a file or buffer or anywhere appropriate
}
}
}
Cancel the job from the main thread:
MainScope().launch {
// Cancel the job and wait for its completion on main thread.
job.cancelAndJoin()
job = null // May be necessary
// TODO: Anything else you may want to clean up
}
This solution should suffice if you want to collect your app's new logs continuously on a background thread.
The "-c" flag clears the buffer.
-c Clears (flushes) the entire log and exits.
//CLEAR LOGS
Runtime.getRuntime().exec("logcat -c");
//LISTEN TO NEW LOGS
Process pq=Runtime.getRuntime().exec("logcat v main");
BufferedReader brq = new BufferedReader(new InputStreamReader(pq.getInputStream()));
String sq="";
while ((sq = brq.readLine()) != null)
{
//CHECK YOUR MSG HERE
if(sq.contains("send MMS with param"))
{
}
}
I am using this in my app and it works .
And you can use above code in Timer Task so that it wont stop your main thread
Timer t;
this.t.schedule(new TimerTask()
{
public void run()
{
try
{
ReadMessageResponse.this.startRecord();//ABOVE METHOD HERE
}
catch (IOException ex)
{
//NEED TO CHECK SOME VARIABLE TO STOP MONITORING LOGS
System.err.println("Record Stopped");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
ReadMessageResponse.this.t.cancel();
}
}
}, 0L);
}
Try to add this permission into the mainfest:
<uses-permission android:name="android.permission.READ_LOGS"/>