I have a task to construct a long properly formatted string in Java. This string will be then used as a header of the logfile that we write during the program execution. As the program runs on server continuously, this string may need to be returned via the overridden method more than once. I have used multiple StringBuilder
s and some flags to make sure I don't do anything repeatedly or unnecessarily. But I am still looking for ways to improve the performance of this code.
@Plugin(name = "property", category = StrLookup.CATEGORY)
public class CustomLookup extends AbstractLookup {
private static final String LINE_SEPARATOR = System
.getProperty("line.separator");
private static AtomicLong aLong = new AtomicLong(0);
private StringBuilder formattedString;
private StringBuilder javaPropsString;
private StringBuilder pathPropsString;
private StringBuilder osPropsString;
private StringBuilder otherPropesString;
// flag to determine if we already have formatted string ready
// as we don't want to create new string every-time.
private boolean isStringReady = false;
// flag to determine if environment variables are added to system
// properties.
private boolean isEnvPropsSet = false;
private Properties properties;
@Override
public String lookup(LogEvent event, String key) {
// if this is the first call (i.e. system startup) we
// don't log the system properties.
if (aLong.getAndIncrement() == 0)
return "";
// on any subsequent calls i.e. on file rollover
// we return the formatted string with system properties.
else if (key.equalsIgnoreCase("customKey")) {
prepareCustomLog();
return formattedString.toString();
} else
return "";
}
/**
* This method prepares the custom string in a readable format. It checks if
* the string is already prepared with the {@link #isStringReady} flag.
*/
private void prepareCustomLog() {
// If already prepared a string in previous call then do nothing here
// as the string will be ready.
if (!isStringReady) {
formattedString = new StringBuilder();
javaPropsString = new StringBuilder();
osPropsString = new StringBuilder();
pathPropsString = new StringBuilder();
otherPropesString = new StringBuilder();
// If environment properties are not added to system properties add
// them now.
if (!isEnvPropsSet)
addEnvProps();
properties = System.getProperties();
Set<Object> set = properties.keySet();
set.removeAll(getIgnoreList());
Iterator<Object> i = set.iterator();
formattedString.append(LINE_SEPARATOR)
.append("/*********** System properties *************/")
.append(LINE_SEPARATOR);
javaPropsString.append(LINE_SEPARATOR).append(" ")
.append("JAVA Properties").append(LINE_SEPARATOR);
osPropsString.append(LINE_SEPARATOR).append(" ")
.append("OS Properties").append(LINE_SEPARATOR);
pathPropsString.append(LINE_SEPARATOR).append(" ")
.append("PATH variables and properties")
.append(LINE_SEPARATOR);
otherPropesString.append(LINE_SEPARATOR).append(" ")
.append("Other Properties").append(LINE_SEPARATOR);
while (i.hasNext()) {
String key = i.next().toString();
// filter out any keys those may contain privacy sensitive
// details.
if (!(key.toLowerCase().contains("user"))
&& !(key.toLowerCase().contains("home"))
&& !(key.toLowerCase().contains("system"))
&& !(key.toLowerCase().contains("program"))) {
if (key.contains("java"))
appendJavaPropsString(key);
else if (key.contains("os"))
appendOsPropsString(key);
else if (key.contains("path"))
appendPathPropsString(key);
else
appendOtherPropesString(key);
}
}
formattedString.append(javaPropsString).append(osPropsString)
.append(pathPropsString).append(otherPropesString);
formattedString.append(
"/*********** System properties *************/").append(
LINE_SEPARATOR);
isStringReady = true;
}
}
private void addEnvProps() {
for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
System.setProperty(entry.getKey(), entry.getValue());
}
}
private void appendJavaPropsString(final String key) {
javaPropsString.append(" ").append(key).append(" : ")
.append(properties.get(key)).append(LINE_SEPARATOR);
}
private void appendOsPropsString(final String key) {
osPropsString.append(" ").append(key).append(" : ")
.append(properties.get(key)).append(LINE_SEPARATOR);
}
private void appendPathPropsString(final String key) {
pathPropsString.append(" ").append(key).append(" : ")
.append(properties.get(key)).append(LINE_SEPARATOR);
}
private void appendOtherPropesString(final String key) {
otherPropesString.append(" ").append(key).append(" : ")
.append(properties.get(key)).append(LINE_SEPARATOR);
}
/**
* This method returns a set of keys that we do not require to log, or the
* keys which may have some sort of private information associated with it.
*
* @return set of keys to ignore when logging.
*/
private Set<Object> getIgnoreList() {
Set<Object> ignore = new HashSet<Object>();
ignore.add("M2");
ignore.add("COMPUTERNAME");
ignore.add("ProgramData");
ignore.add("HOMEPATH");
ignore.add("LOGONSERVER");
ignore.add("LOCALAPPDATA");
ignore.add("PUBLIC");
ignore.add("APPDATA");
return ignore;
}
}
class
name statement but anyway I have added that too. so this is now a complete code of this class. \$\endgroup\$