Log4j Custom Appender Properties File Issue - layout

So I created a custom appender for Log4J that essentially does the same thing as the socketappender, but with UDP as opposed to TCP. However, I cannot get the log to display the date. I think that there might be an issue with the .properties file, but I'm not sure what. Especially since I know the .properties file is working to some extent because that is how the test program knows which appender to use. However, it is not using the layout specified in the .properties file. Any help/suggestions would be greatly appreciated!
Appender code:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
public /*static*/ class UDPAppender extends AppenderSkeleton {
#Override
protected void append(LoggingEvent event) {
String message = null;
event.getProperties();
StringBuilder formatedMessage = new StringBuilder();
formatedMessage.append("Level:");
formatedMessage.append(event.getLevel());
formatedMessage.append(", FILE:");
formatedMessage.append(event.getLocationInformation().getFileName());
formatedMessage.append(", Thread Id:");
formatedMessage.append(event.getLocationInformation().getLineNumber());
formatedMessage.append(", ERROR: ");
formatedMessage.append(event.getMessage().toString());
message = formatedMessage.toString();
DatagramSocket clientSocket = null;
//creating DatagramSocket to send logger info to socket; if not created, will print Stack Trace
try {
clientSocket = new DatagramSocket();
} catch (SocketException e) {
e.printStackTrace();
}
InetAddress IPAddress = null;
//get InetAddress for sending packet
try {
IPAddress = InetAddress.getByName("localhost");
} catch (UnknownHostException e) {
e.printStackTrace();
}
byte[] sendData = new byte[1024];
sendData = message.getBytes(); //convert from String to bytes so that message can be sent through datagrampacket
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 27770); //address packet
try {
clientSocket.send(sendPacket); //send packet to the socket addressed above
} catch (IOException e) {
e.printStackTrace();
}
clientSocket.close(); //need to close
}
public void close() {
}
public boolean requiresLayout() {
return true;
}
}
Test code:
import org.apache.log4j.*;
public class Tester {
private static final Logger log2 = Logger.getLogger("REMOTE");
public static void main(String[] args) {
//configures using the .properties file user creates
PropertyConfigurator.configure("log4j.properties");
log2.info("This is info message");
System.out.println("Logging complete");
//prints to console to let user know logging completed successfully
LogManager.shutdown();
//closes logs once logging is complete
}
}
.properties file:
log4j.logger.REMOTE=DEBUG, REMOTE
log4j.appender.REMOTE=custom.UDPAppender
log4j.appender.REMOTE.layout=org.apache.log4j.PatternLayout
log4j.appender.REMOTE.layout.ConversionPattern=%d{MMMM dd HH:mm:ss}, %d{yyyy} %F %L %m %t

I was actually able to just convert the time stamp to day/time with the following code:
long date = event.getTimeStamp();
Date dateObj = new Date(date);
DateFormat df = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss");
StringBuilder formatedMessage = new StringBuilder();
formatedMessage.append("Time:");
formatedMessage.append(df.format(dateObj));

Related

Live Streaming audio from java server to Android Client

I want to stream audio from my computer to android clients. I have taken the input and now I want that to be transmitted over the stream and be played. Now my problem is that on the input side I have AudioInputStream class and other classes which I am able to use but on the android side it says that they are private and cannot be accessed outside the class. I want to play the coming audio on android. What should I do. I just want to support 1 client for now.
Server:
import java.net.*;
import java.io.*;
import javax.sound.sampled.*;
public class MainServer{
private static AudioFormat getAudioFormat() {
AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
float rate = 44100.0f;
int channels = 2;
int sampleSize = 16;
boolean bigEndian = true;
InetAddress addr;
AudioFormat format = new AudioFormat(encoding, rate, sampleSize, channels, (sampleSize / 8) * channels, rate, bigEndian);
return format;
}
private static TargetDataLine configureStreams(){
try{
AudioFormat format = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
// checks if system supports the data line
if (!AudioSystem.isLineSupported(info)) {
System.out.println("Line not supported");
System.exit(0);
}
TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format);
line.start();
System.out.println("Got the line and started to listen");
return line;
}
catch(Exception e){
System.err.println(e);
}
return null;
}
public static void main(String args[]){
try{
ServerSocket server = new ServerSocket(3000);
System.out.println("Server is listening");
TargetDataLine audio = configureStreams();
while(true){
Socket socket = server.accept();
System.out.println("Current accepted socket: "+socket);
HandlingClient client = new HandlingClient(socket, audio);
client.start();
}
}
catch(Exception e){
System.err.println(e);
}
}
}
class HandlingClient extends Thread{
AudioFileFormat.Type fileType = AudioFileFormat.Type.WAVE;
private Socket socket;
private OutputStream output;
private TargetDataLine audio;
HandlingClient(Socket socket, TargetDataLine audio){
this.socket=socket;
this.audio=audio;
}
public void run(){
try{
AudioInputStream ais = new AudioInputStream(audio);
output=socket.getOutputStream();
byte[]data = new byte[1024];
System.out.println("Start recording and sending");
while(true){
data=ais.readNBytes(1024);
output.write(data);
}
}
catch(Exception e){
System.err.println(e);
System.out.println("OutputStream: "+output);
System.out.println("Socket: "+socket);
}
}
}
Android Client:
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.StrictMode;
import android.view.View;
import android.widget.EditText;
import java.io.IOException;
import java.net.Socket;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StrictMode.ThreadPolicy myCustomizableThread = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(myCustomizableThread);
//Starting from here
}
public void connect(View view){
final EditText editText = findViewById(R.id.url);
String url = editText.getText().toString().trim(); //User enters the url in the form like 192.168.43.102:3000
String target = url.substring(0, url.indexOf(':'));
int port = Integer.parseInt(url.substring(url.indexOf(':')+1, url.length()));
try {
Socket socket = new Socket(target, port);
//Media player here to play the recording
} catch (IOException e) {
e.printStackTrace();
}
}
}

How to set additivity to false when the Appender is added programatically

I am new to log4j. My requirement is to create a new log file during every iteration. Basically during every iteration, below is what I need to attain:
Create a folder with current timestamp as the folder's name
Create a log file with name log.txt
Log the transactions of that iteration in log.txt
I have given a mock up of the implementation i need.
log4j.properties
log4j.rootLogger=INFO
log4j.appender.tracerLog=org.apache.log4j.FileAppender
log4j.appender.tracerLog.File=logs/${log4j.test.start.timestamp}/tracer.log
log4j.appender.tracerLog.layout=org.apache.log4j.PatternLayout
log4j.appender.tracerLog.layout.ConversionPattern=%d %-5p - %m%n
log4j.category.traceLogger=TRACE, tracerLog
log4j.additivity.traceLogger=false
java code
package app.testscript;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.log4j.FileAppender;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
public class Log4jTest {
static{
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_hh_mm_ss_S");
System.setProperty("log4j.test.start.timestamp", dateFormat.format(new Date()));
}
Logger traceLogger = Logger.getLogger("traceLogger");
Logger rootLogger = Logger.getRootLogger();
Logger testScriptLogger = null;
public void doSomething() {
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_hh_mm_ss_S");
PatternLayout patterLayout = new PatternLayout("%m%n");
String folderNameToCreate = dateFormat.format(new Date());
FileAppender fileAppender = new FileAppender(patterLayout, "C:/MyTestLog/" + folderNameToCreate + "/log.txt", true);
fileAppender.setName("A" + folderNameToCreate);
fileAppender.activateOptions();
rootLogger.addAppender(fileAppender);
try {
testScriptLogger = LogManager.getLogger("A" + folderNameToCreate);
}catch(Exception e1) {
System.out.println("Exception e: ");
e1.printStackTrace();
}
//testScriptLogger.setAdditivity(false);
testScriptLogger.info("Message to capture in log - " + folderNameToCreate);
}catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Log4jTest obj = new Log4jTest();
for (int i=0; i<2; i++) {
obj.doSomething();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Result of the above Code:
I can see there are 2 folders created (folder_1 and folder_2)
Both the folders have the log.txt in it
log.txt file created (inside folder_1) during iteration 1 have 2 lines in it (log related to iteration 1 and iteration 2)
log.txt file created (inside folder_2) during iteration 2 have one line it (log related to iteration 2)
Expected Result is to have 1 line in both the log.txt files (created during iteration 1 and 2)
When using testScriptLogger.setAdditivity(false); , I get the below WARNING message and nothing is written to the file.
log4j:WARN No appenders could be found for logger (A20170518_03_49_10_802).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Please help me with a solution. Thanks
Found the answer.
Java code:
package app.testscript;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
public class Log4jTest {
static{
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_hh_mm_ss_S");
System.setProperty("log4j.test.start.timestamp", dateFormat.format(new Date()));
}
Logger scriptLogger = Logger.getLogger("scriptLogger");
String prevAppenderName = "";
public void removeBaseAppenderConfiguredInlog4jProperties() {
scriptLogger.removeAppender("scriptLog");
}
public void doSomething() {
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_hh_mm_ss_S");
PatternLayout patterLayout = new PatternLayout("%m%n");
String folderNameToCreate = dateFormat.format(new Date());
FileAppender fileAppender = new FileAppender(patterLayout, "C:/MyTestLog/" + folderNameToCreate + "/log.txt", true);
fileAppender.setName("A" + folderNameToCreate);
fileAppender.activateOptions();
if(!prevAppenderName.equalsIgnoreCase("")) {
scriptLogger.removeAppender(prevAppenderName);
}
scriptLogger.addAppender(fileAppender);
prevAppenderName="A" + folderNameToCreate;
scriptLogger.setAdditivity(false);
scriptLogger.info("Message to capture in log - " + folderNameToCreate);
}catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Log4jTest obj = new Log4jTest();
obj.removeBaseAppenderConfiguredInlog4jProperties();
for (int i=0; i<2; i++) {
obj.doSomething();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

How could I turn this into a thread so it doesn't freeze up my app?

So I was wanting to know how I would go about turning this into a thread? I have tried and failed multiple times. I am about read to give up and just deal with the application freezing while it gets a response.
package me.robert.tb.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
public class HTTPConnect {
private static BufferedReader reader = null;
private static StringBuilder buffer = new StringBuilder();
/**
* This method is used to connect to a website and return its response.
* Mainly used for connecting to API's
*
* #param link
* The URL of the website
* #return The response from the website
*/
public static String getResponse(String link) {
try {
reader = new BufferedReader(new InputStreamReader(new URL(link).openStream()));
int read;
char[] chars = new char[1024];
while ((read = reader.read(chars)) != -1)
buffer.append(chars, 0, read);
} catch (Exception e) {
} finally {
try {
if (reader != null)
reader.close();
} catch (IOException e) {
}
}
return buffer.toString();
}
}
Any help is greatly appreciated!
Here you go. Though you shouldn't really need threads to import 1024 characters. On a few test pages it ran pretty quickly. I think your main issue is trying to make getResponse() static. Anyway, here's your modified code using a thread.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
public class HTTPConnect implements Runnable{
private static BufferedReader reader = null;
private static StringBuilder buffer = new StringBuilder();
private String link;
private String response;
/**
* This method is used to connect to a website and return its response.
* Mainly used for connecting to API's
*
* #param link
* The URL of the website
* #return The response from the website
*/
public HTTPConnect(String input){
link = input;
}
public void run() {
try {
reader = new BufferedReader(new InputStreamReader(new URL(link).openStream()));
int read;
char[] chars = new char[1024];
while ((read = reader.read(chars)) != -1)
buffer.append(chars, 0, read);
} catch (Exception e) {
} finally {
try {
if (reader != null)
reader.close();
response = buffer.toString();
} catch (IOException e) {
}
}
}
public String getResponse(){
return response;
}
public static void main (String[] args){
String website = "http://google.com";
Thread t = new Thread(new HTTPConnect(website));
t.run();
}
}

Create an custom appender in log4j which stores the log in memory

I want to create an custom appender using log4j in java programatically which stores the log in memory(Certain size will be defined for e.g. say DEFAULT_SIZE=20) & as soon as memory is full(there are 20 logs in memory) create an json array of those logs and send it to the server. Along with log message i also want information such as (class, file name,line number,method name,level etc.)
Help is appreciated.!!!
Updated ::
Below is the source code developed by me for the same . Problem which i am facing is i get line number, method name,file name as "?".I dont understand what is the reason.
package com.any.logger;
import java.util.ArrayList;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
public class Log4jAppender extends AppenderSkeleton {
private static final int DEFAULT_BUFFER_SIZE = 20;
private ArrayList<LoggingEvent> buffer;
private int bufferSize;
public Log4jAppender() {
this.bufferSize = Log4jAppender.DEFAULT_BUFFER_SIZE;
this.buffer = new ArrayList<LoggingEvent>();
}
public void close() {
}
public boolean requiresLayout() {
return false;
}
#Override
protected void append(LoggingEvent loggingEvent) {
synchronized (buffer) {
if (buffer.size() >= bufferSize) {
try {
System.out.println("Hello");
Log4jService service = new Log4jService(new ArrayList<LoggingEvent>
(buffer));
System.out.println("Buff >");
service.start();
} catch (Exception e) {
System.err.println("Failed to write logs");
e.printStackTrace();
} finally {
buffer.clear();
}
}
}
buffer.add(loggingEvent);
}
}
package com.any.logger;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.log4j.Level;
import org.apache.log4j.spi.LoggingEvent;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
#SuppressWarnings("rawtypes")
public class Log4jService implements Runnable {
private ArrayList<LoggingEvent> buffer;
private Thread t;
private boolean flag;
public Log4jService(ArrayList<LoggingEvent> buffer) {
this.buffer = new ArrayList<LoggingEvent>(buffer);
this.flag = false;
}
public void start() {
if (!flag) {
this.flag = true;
this.t = new Thread(this);
this.t.start();
}
}
public void run() {
if (flag) {
String json = getLogJson(buffer);
}
}
/**
* Method to get the json log
*
* #param logEvents
* arrayList of log events
* #return an String which is json file
* #throws JSONException
*/
private String getLogJson(ArrayList<LoggingEvent> logEvents) {
System.out.println("In getLogJson");
JSONObject logger = new JSONObject();
try {
JSONArray logs = new JSONArray();
String message = "";
String time = "";
String level = "";
String tag = "";
String file = "";
String exceptionName = "";
String exceptionReason = "";
String line = "";
String clas = "";
String method = "";
int index = 0;
SimpleDateFormat formatter=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (Iterator i = logEvents.iterator(); i.hasNext();) {
LoggingEvent logEvent = (LoggingEvent) i.next();
boolean chk=logEvent.locationInformationExists();
System.out.println("Check :: "+chk);
clas=logEvent.getClass().toString();
JSONObject log = new JSONObject();
message = logEvent.getMessage().toString();
time = String.valueOf(formatter.format(logEvent.getTimeStamp()));
level = logEvent.getLevel().toString();
if (chk) {
System.out.println("hello");
file = logEvent.getLocationInformation().getFileName();
line = logEvent.getLocationInformation().getLineNumber();
method = logEvent.getLocationInformation().getMethodName();
}
if (logEvent.getLevel() == Level.ERROR || logEvent.getLevel() ==
Level.FATAL) {
exceptionReason = message;
}
log.put("message", message);
log.put("time", time);
log.put("level", level);
log.put("tag", tag);
log.put("file", file);
log.put("exceptionName", exceptionName);
log.put("exceptionReason", exceptionReason);
log.put("line", line);
log.put("class", clas);
log.put("method", method);
logs.put(index, log);
index++;
}
JSONObject logsObj = new JSONObject();
logsObj.put("logs", logs);
logger.put("log", logsObj);
System.out.println("Logs Array :: " + logsObj);
System.out.println("Logger Object :: " + logger);
} catch (Exception e) {
e.printStackTrace();
}
return logger.toString();
}
}
I would look at the source code for log4j2 and use an existing appender as a template for my custom appender. SocketAppender and TCPSocketManager may be good places to start.
http://logging.apache.org/log4j/2.0/log4j-core/xref/org/apache/logging/log4j/core/net/TCPSocketManager.html
Currently the buffering is based on the number of bytes, not event count. If you follow the existing appender/manager pattern then in your custom appender manager you will need to have a large enough buffer and flush every 20 events. (Perhaps also flush after some timeout? You may only get 19 events and nothing after that...)
You could also do the buffering in the appender, keep a list of event objects there and only call pass them to the manager to be written after some threshold is reached.
The default Layout for SocketAppender will use java serialization. You'll need to roll your own JasonLayout. The log event object has all the details you mentioned.

Why I am getting the bad length exception when I am running this application?

I want to communicate to a server from J2me app using UDP.However, when I am running the app, I am getting a bad length exception.My codes and output are given below.
client code
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
import javax.microedition.io.Connector;
import javax.microedition.io.Datagram;
import javax.microedition.io.DatagramConnection;
import java.io.IOException;
public class DatagramTest extends MIDlet
implements CommandListener, Runnable
{
private static final int BUF_SIZE = 1024;
private static Command exit = new Command("Exit", Command.EXIT, 1);
private static DatagramTest instance;
private Display display;
private TextBox dgramText;
private DatagramConnection conn;
private Datagram dgram;
private String address = "datagram://myip:9876";
public DatagramTest()
{
super();
instance = this;
}
public DatagramTest(String service)
{
this();
address = service;
}
/**
Returns the single instance of this class. Calling
this method before constructing an object will return
a null pointer.
#return an instance of this class.
*/
public static DatagramTest getInstance()
{
return instance;
}
public void startApp()
{
display = Display.getDisplay(this);
dgramText = new TextBox("Datagram contents",
null,
2048,
TextField.ANY);
dgramText.setCommandListener(this);
display.setCurrent(dgramText);
System.out.println("Starting run....");
run();
System.out.println("Stopping run....");
}
public void run()
{
System.out.println("In run....");
try
{
int maxLength;
conn = (DatagramConnection)Connector.open(address);
maxLength = conn.getMaximumLength();
dgram = conn.newDatagram(1024);
dgram.reset();
conn.send(dgram);
conn.receive(dgram);
byte[] data = dgram.getData();
// Extract the response string.
String str = new String(data);
System.out.println(str);
dgram.reset();
System.out.println("Exit run....");
}
catch (IOException ioe)
{
System.out.println(ioe.getMessage());
ioe.printStackTrace();
quit();
}
return;
}
public void pauseApp()
{
}
void quit()
{
destroyApp(true);
notifyDestroyed();
}
public void destroyApp(boolean destroy)
{
try
{
conn.close();
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
public void display()
{
Display.getDisplay(this).setCurrent(dgramText);
}
public void commandAction(Command c, Displayable d)
{
if (c == exit)
{
quit();
}
}
}
Server code
import java.io.*;
import java.net.*;
class UDPServer
{
public static void main(String args[]) throws Exception
{
DatagramSocket serverSocket = new DatagramSocket(9876);
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
while(true)
{
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String sentence = new String( receivePacket.getData());
System.out.println("RECEIVED: " + sentence);
InetAddress IPAddress = receivePacket.getAddress();
int port = receivePacket.getPort();
String capitalizedSentence = sentence.toUpperCase();
sendData = capitalizedSentence.getBytes();
DatagramPacket sendPacket =
new DatagramPacket(sendData, sendData.length, IPAddress, port);
serverSocket.send(sendPacket);
}
}
}
Output at clientside
Starting run.... In run.... Bad
datagram length java.io.IOException:
Bad datagram length
at com.sun.midp.io.j2me.datagram.Protocol.receive(Protocol.java:367)
at hello.DatagramTest.run(DatagramTest.java:89)
at hello.DatagramTest.startApp(DatagramTest.java:69)
at javax.microedition.midlet.MIDletProxy.startApp(MIDletProxy.java:43)
at com.sun.midp.midlet.Scheduler.schedule(Scheduler.java:374)
at com.sun.midp.main.Main.runLocalClass(Main.java:466)
at com.sun.midp.main.Main.main(Main.java:120)
Stopping run....
Why I am getting this bad length exception and how do I sort it out?
One thing you need to try is to send and receive datagrams in a separate thread.
The documentation for DatagramConnection.receive() says: "This method blocks until a datagram is received"
You are calling it from inside MIDlet.startApp().
Blocking the application management system thread that calls startApp() is bad practice.

Resources