I need to log my messages not only into system logs ( as I know, system log buffer is quite short, but I need to see logs for 3-5 days ), but also in a separate text file. Logging must be asynchronous.
Could you give me an advice about which component should I use in this case?
Thanks.
I hope it will be useful for you.
public void appendLog(String text) {
File logFile = new File("sdcard/log.file");
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();
}
}
Don't forget to add permission for android.permission.WRITE_EXTERNAL_STORAGE in Manifest!
Works asynchronously and dose not need to permission !
just remember call the init method from your application in onCreateMethod for initializing the Logger
class Logger {
private static File logFileLoc;
private static ExecutorService logExecutor;
public static void init(Context applicationContext, String logFileName, boolean reCreate) {
logFileLoc = new File(applicationContext.getCacheDir(), logFileName);
if (reCreate && logFileLoc.exists()) logFileLoc.delete();
logExecutor = Executors.newSingleThreadExecutor();
}
public static void log(final String tag, final String msg) {
if (logFileLoc == null) try {
throw new Exception("First you should call init method in your application");
} catch (Exception e) {
e.printStackTrace();
}
Log.d(tag, msg);
logExecutor.execute(new Runnable() {
#Override
public void run() {
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(logFileLoc,true));
String timeStamp = DateFormat.getDateTimeInstance().format(new Date(System.currentTimeMillis()));
writer.append(timeStamp + " " + tag + " : " + msg );
writer.newLine();
writer.flush();
writer.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
also you can do the same thing with Timber library for more info :
https://medium.com/#vicky7230/file-logging-with-timber-4e63a1b86a66
Related
I tried to connect with asynchronous socket and read new messages once per second.
I used sample client code (http://www.java2s.com/Tutorials/Java/Java_Network/0080__Java_Network_Asynchronous_Socket_Channels.htm) and in getTextFromUser method I added sleep method (with 1000 ms) and removed read command from user.
Additionally I added additional logic in ReadWriteHandler method. It started work great, but after about one hour program was suspended and has worked (execute my additional logic) not once per second but one per about 10 minutes.
Do you have any idea what might happen?
Part of code:
public void ConnectAsynchr() {
try {
this.channel = AsynchronousSocketChannel.open();
SocketAddress serverAddr = new InetSocketAddress("localhost", PortNumberAsynchr);
Future<Void> result = channel.connect(serverAddr);
try {
result.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.writeLog("ConnAsynch", "Asynchronous connection succesful established", true);
this.connectAsynch = true;
this.attach = new Attachment();
this.attach.channel = this.channel;
this.attach.buffer = ByteBuffer.allocate(16384);
this.attach.isRead = false;
this.attach.mainThread = Thread.currentThread();
ReadWriteHandler readWriteHandler = new ReadWriteHandler();
this.channel.write(this.attach.buffer, this.attach, readWriteHandler);
try {
this.attach.mainThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
this.writeLog("ERROR", e.toString(), false);
e.printStackTrace();
}
}
catch (IOException e) {
this.writeLog("ERROR", e.toString(), false);
System.out.println(e);
}
}
class Attachment {
AsynchronousSocketChannel channel;
ByteBuffer buffer;
Thread mainThread;
boolean isRead;
}
class ReadWriteHandler implements CompletionHandler<Integer, Attachment> {
#Override
public void completed(Integer result, Attachment attach) {
if (attach.isRead) {
attach.buffer.flip();
Charset cs = Charset.forName("UTF-8");
int limits = attach.buffer.limit();
byte bytes[] = new byte[limits];
attach.buffer.get(bytes, 0, limits);
String msg = new String(bytes, cs);
writeLog("Asynchr Msg rec", msg, false);
AsynchrMessLogic(msg);
try {
msg = this.getTextFromUser();
} catch (Exception e) {
e.printStackTrace();
}
if (msg.equalsIgnoreCase("bye")) {
attach.mainThread.interrupt();
return;
}
attach.buffer.clear();
byte[] data = msg.getBytes(cs);
attach.buffer.put(data);
attach.buffer.flip();
attach.isRead = false; // It is a write
attach.channel.write(attach.buffer, attach, this);
}else {
attach.isRead = true;
attach.buffer.clear();
attach.channel.read(attach.buffer, attach, this);
}
}
#Override
public void failed(Throwable e, Attachment attach) {
e.printStackTrace();
}
private String getTextFromUser() throws Exception{
/*System.out.print("\nPlease enter a message (Bye to quit):");
BufferedReader consoleReader = new BufferedReader(
new InputStreamReader(System.in));
String msg = consoleReader.readLine();
*/
Thread.sleep(threadSleep);
String msg="aaa";
return msg;
}
}
I want to write something to the end of the file every time the file is modified and I'm using this code :
public class Main {
public static final String DIRECTORY_TO_WATCH = "D:\\test";
public static void main(String[] args) {
Path toWatch = Paths.get(DIRECTORY_TO_WATCH);
if (toWatch == null) {
throw new UnsupportedOperationException();
}
try {
WatchService myWatcher = toWatch.getFileSystem().newWatchService();
FileWatcher fileWatcher = new FileWatcher(myWatcher);
Thread t = new Thread(fileWatcher, "FileWatcher");
t.start();
toWatch.register(myWatcher, StandardWatchEventKinds.ENTRY_MODIFY);
t.join();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
and the thread class :
public class FileWatcher implements Runnable{
private WatchService myWatcher;
private Path toWatch;
String content = "Dong\n";
int counter = 0;
public FileWatcher (WatchService myWatcher, Path toWatch) {
this.myWatcher = myWatcher;
this.toWatch = toWatch;
}
#Override
public void run() {
try {
WatchKey key = myWatcher.take();
while (key != null) {
for (WatchEvent event : key.pollEvents()) {
//System.out.printf("Received %s event for file: %s\n", event.kind(), event.context());
//System.out.println(counter);
myWatcher = null;
File file = new File(Main.DIRECTORY_TO_WATCH + "\\" + event.context());
FileWriter fw = new FileWriter(file.getAbsoluteFile(), true);
fw.write(counter + content);
fw.close();
counter++;
myWatcher = toWatch.getFileSystem().newWatchService();
toWatch.register(myWatcher, StandardWatchEventKinds.ENTRY_MODIFY);
// BufferedWriter bwWriter = new BufferedWriter(fw);
// bwWriter.write(content);
// bwWriter.close();
}
key.reset();
key = myWatcher.take();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I want to get in the file something like :
acasc 0dong
dwqcacesv 1dong
terert 2dong
However, now I'm getting this, because it writes too many times in the file:
acasc 0dong
1dong
...
50123dong
If I use System.out.println(counter); it works as I want to (prints the number of file changes correctly), but it goes wild on fw.write(counter + content);
Your thread's write is causing further changes to the file.
Self feeding loop.
I want to do following operation in ordered wise
1. Stop jetty server
2. Delete used resource from jetty
3. Restart jetty server.
I have done this above using shutdownhook in java as below :
<code>
Thread restartThread = new Thread(){
public void run(){
try {
sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String osName = System.getProperty("os.name");
logger.debug("OS name:" + osName);
if (osName != null
&& osName.toUpperCase().startsWith("WINDOWS")) {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
List<String> cmdLine = new ArrayList<String>();
cmdLine.add("cmd.exe");
cmdLine.add("/C");
cmdLine.add("start");
cmdLine.add("\"\"");
cmdLine.add(getBaseDir() + File.separator + "restart.bat");
final ProcessBuilder pb = new ProcessBuilder(cmdLine);
Process process = pb.start();
if (process.exitValue() == 0) {
// after stopping server delete stores
deleteCertificates();
// restores files
restoreFiles(tmpdir, backupfilelist);
}
//p.waitFor();
} catch (IOException e) {
logger.error("Failed to restart:" + e.getMessage(), e);
}
}
});
System.exit(0);
} else {
try {
Runtime.getRuntime().exec("service appservice restart");
} catch (IOException e) {
logger.error("Failed to restart:" + e.getMessage(), e);
}
}
}
};
restartThread.start();
<code>
my concern is will it do it sequentially execution, otherwise application will fail to restore.
I used a function where logger and parameters are initialized.
Although I called this function LogMsg and newline in console, but it gives one single line in the text file. Why is that so?
String logmsg="Line1\n"+"Line2\n";
public static void LogMsg(Logger logger,String pathname,Level level,String logmsg){
//logger=Logger.getLogger("LogMsg");
FileHandler fh=null;
try {
fh = new FileHandler(pathname,300000,1,true);
fh.setFormatter(new SimpleFormatter());
LogRecord record1 = new LogRecord(level, logmsg);
logger.addHandler(fh);
logger.log(record1);
fh.close();
} catch (SecurityException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
System.out.println("Failed to log message due to lack of permissions.");
} catch (IOException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
System.out.println("Failed to log message");
}
}
Try
String logmsg="Line1\r\n"+"Line2\r\n";
or better still
logmsg = String.Concat("Line1",Environment.NewLine,"Line2",Environment.NewLine);
Or better still use a StringBuilder somethimng like
logmsg = CreateLogMessage(new string [] {"Line1", "Line2"});
public static CreateLogMessage(string[] argLines);
{
StringBuilder sb = new StringBuilder(argLines.Length);
foreach(String line in argLines)
{
sb.AppendLine(line);
}
return sb.ToString();
}
Environment.Newline will deal with os differences in terms of which end of line token is expected.
I'm trying to enter some value in external application using Java.
Java application looks like this:
Runtime runtime = Runtime.getRuntime();
// ... str build ...
proc = runtime.exec(str);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
bw.write(value);
bw.flush();
bw.close();
if (proc.waitFor() != 0)
// error msg
// the end
Application hangs at waitFor method.
External application looks like this:
welcome banner
please enter 8 character input:
Welcome banner is printed using printf and input is taken with SetConsoleMode/ReadConsoleInput. ReadConsoleInput reads one char and they are masked with * character.
Help
you can use:
proc.getOutputStream().write("some date".getBytes())
keep in mind that you HAVE to read everything the app send to stdout and stderr, else it might get stuck writing there.
I use a generic class to read it in a different thread.
usage is like:
InputStreamSucker inSucker = new InputStreamSucker(proc.getInputStream());
InputStreamSucker errSucker = new InputStreamSucker(proc.getErrorStream());
proc.waitFor();
int exit = process.exitValue();
inSucker.join();
errSucker.join();
InputStreamSucker code is here:
public class InputStreamSucker extends Thread
{
static Logger logger = Logger.getLogger(InputStreamSucker.class);
private final BufferedInputStream m_in;
private final ByteArrayOutputStream m_out;
private final File m_outFile;
public InputStreamSucker(InputStream in) throws FileNotFoundException
{
this(in, null);
}
public InputStreamSucker(InputStream in, File outFile) throws FileNotFoundException
{
m_in = new BufferedInputStream(in, 4096);
m_outFile = outFile;
m_out = new ByteArrayOutputStream();
start();
}
#Override
public void run()
{
try
{
int c;
while ((c = m_in.read()) != -1)
{
m_out.write(c);
}
}
catch (IOException e)
{
logger.error("Error pumping stream", e);
}
finally
{
if (m_in != null)
{
try
{
m_in.close();
}
catch (IOException e)
{
}
}
try
{
m_out.close();
}
catch (IOException e)
{
logger.error("Error closing out stream", e);
}
if (m_outFile != null)
{
byte data[] = m_out.toByteArray();
if (data.length > 0)
{
FileOutputStream fo = null;
try
{
fo = new FileOutputStream(m_outFile);
fo.write(data);
}
catch (IOException e)
{
logger.error("Error writing " + m_outFile);
}
finally
{
try
{
if (fo != null) fo.close();
}
catch (IOException e)
{
logger.error("Error closing " + m_outFile);
}
}
}
}
}
}
public String getOutput()
{
return new String(m_out.toByteArray());
}
}
Got the answer! The trick is to use WriteConsoleInput() API because program expects keyboard event, not text ... That's why the waitFor() waited forever! :)