You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LogFileLocator.java 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * Copyright (c) 2006-2017 DMDirc Developers
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
  5. * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
  6. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
  7. * permit persons to whom the Software is furnished to do so, subject to the following conditions:
  8. *
  9. * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
  10. * Software.
  11. *
  12. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  13. * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
  14. * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  15. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  16. */
  17. package com.dmdirc.addons.logging;
  18. import com.dmdirc.commandline.CommandLineOptionsModule.Directory;
  19. import com.dmdirc.config.binding.ConfigBinding;
  20. import com.dmdirc.config.GlobalConfig;
  21. import com.dmdirc.interfaces.Connection;
  22. import com.dmdirc.interfaces.GroupChat;
  23. import com.dmdirc.interfaces.User;
  24. import com.dmdirc.config.provider.AggregateConfigProvider;
  25. import com.dmdirc.plugins.PluginDomain;
  26. import java.io.File;
  27. import java.math.BigInteger;
  28. import java.security.MessageDigest;
  29. import java.security.NoSuchAlgorithmException;
  30. import java.text.SimpleDateFormat;
  31. import java.util.Date;
  32. import java.util.Optional;
  33. import javax.annotation.Nullable;
  34. import javax.inject.Inject;
  35. import javax.inject.Provider;
  36. import javax.inject.Singleton;
  37. import org.slf4j.Logger;
  38. import org.slf4j.LoggerFactory;
  39. import static com.dmdirc.util.LogUtils.USER_ERROR;
  40. /**
  41. * Facilitates finding a path for log files.
  42. */
  43. @Singleton
  44. public class LogFileLocator {
  45. private static final Logger LOG = LoggerFactory.getLogger(LogFileLocator.class);
  46. private final Provider<String> directoryProvider;
  47. /** Whether to append a hash of the file name to the file name... */
  48. @ConfigBinding(key = "advanced.filenamehash")
  49. private boolean filenamehash;
  50. /** Whether to create a new folder for each network. */
  51. @ConfigBinding(key = "general.networkfolders")
  52. private boolean networkfolders;
  53. /** Whether to use date formats in file names. */
  54. @ConfigBinding(key = "advanced.usedate")
  55. private boolean usedate;
  56. /** Date format to use in file names if {@link #usedate} is true. */
  57. @ConfigBinding(key = "advanced.usedateformat")
  58. private String usedateformat;
  59. @Inject
  60. public LogFileLocator(
  61. @Directory(LoggingModule.LOGS_DIRECTORY) final Provider<String> directoryProvider,
  62. @GlobalConfig final AggregateConfigProvider globalConfig,
  63. @PluginDomain(LoggingPlugin.class) final String domain) {
  64. this.directoryProvider = directoryProvider;
  65. globalConfig.getBinder().withDefaultDomain(domain).bind(this, LogFileLocator.class);
  66. }
  67. /**
  68. * Sanitises the log file directory.
  69. *
  70. * @return Log directory
  71. */
  72. private StringBuffer getLogDirectory() {
  73. final StringBuffer directory = new StringBuffer();
  74. directory.append(directoryProvider.get());
  75. if (directory.charAt(directory.length() - 1) != File.separatorChar) {
  76. directory.append(File.separatorChar);
  77. }
  78. return directory;
  79. }
  80. /**
  81. * Get the name of the log file for a specific object.
  82. *
  83. * @param channel Channel to get the name for
  84. *
  85. * @return the name of the log file to use for this object.
  86. */
  87. public String getLogFile(final GroupChat channel) {
  88. final StringBuffer directory = getLogDirectory();
  89. final StringBuffer file = new StringBuffer();
  90. final Optional<String> network = channel.getConnection().map(Connection::getNetwork);
  91. network.ifPresent(n -> addNetworkDir(directory, file, n));
  92. file.append(sanitise(channel.getName().toLowerCase()));
  93. return getPath(directory, file, channel.getName());
  94. }
  95. /**
  96. * Get the name of the log file for a specific object.
  97. *
  98. * @param user Client to get the name for
  99. *
  100. * @return the name of the log file to use for this object.
  101. */
  102. public String getLogFile(final User user) {
  103. final StringBuffer directory = getLogDirectory();
  104. final StringBuffer file = new StringBuffer();
  105. addNetworkDir(directory, file, user.getConnection().getNetwork());
  106. file.append(sanitise(user.getNickname().toLowerCase()));
  107. return getPath(directory, file, user.getNickname());
  108. }
  109. /**
  110. * Gets the path for the given file and directory. Only intended to be used from getLogFile
  111. * methods.
  112. *
  113. * @param directory Log file directory
  114. * @param file Log file path
  115. * @param md5String Log file object MD5 hash
  116. *
  117. * @return Name of the log file
  118. */
  119. public String getPath(final StringBuffer directory, final StringBuffer file,
  120. final String md5String) {
  121. if (usedate) {
  122. final String dateFormat = usedateformat;
  123. final String dateDir = new SimpleDateFormat(dateFormat).format(new Date());
  124. directory.append(dateDir);
  125. if (directory.charAt(directory.length() - 1) != File.separatorChar) {
  126. directory.append(File.separatorChar);
  127. }
  128. if (!new File(directory.toString()).exists()
  129. && !new File(directory.toString()).mkdirs()) {
  130. LOG.info(USER_ERROR, "Unable to create data dirs");
  131. }
  132. }
  133. if (filenamehash) {
  134. file.append('.');
  135. file.append(md5(md5String));
  136. }
  137. file.append(".log");
  138. return directory + file.toString();
  139. }
  140. /**
  141. * This function adds the networkName to the log file. It first tries to create a directory for
  142. * each network, if that fails it will prepend the networkName to the filename instead.
  143. *
  144. * @param directory Current directory name
  145. * @param file Current file name
  146. * @param networkName Name of network
  147. */
  148. protected void addNetworkDir(final StringBuffer directory, final StringBuffer file,
  149. final String networkName) {
  150. if (!networkfolders) {
  151. return;
  152. }
  153. final String network = sanitise(networkName.toLowerCase());
  154. boolean prependNetwork = false;
  155. // Check dir exists
  156. final File dir = new File(directory + network + System.getProperty(
  157. "file.separator"));
  158. if (dir.exists() && !dir.isDirectory()) {
  159. LOG.info(USER_ERROR, "Unable to create networkfolders dir (file exists instead)");
  160. // Prepend network name to file instead.
  161. prependNetwork = true;
  162. } else if (!dir.exists() && !dir.mkdirs()) {
  163. LOG.info(USER_ERROR, "Unable to create networkfolders dir");
  164. prependNetwork = true;
  165. }
  166. if (prependNetwork) {
  167. file.insert(0, " -- ");
  168. file.insert(0, network);
  169. } else {
  170. directory.append(network);
  171. directory.append(System.getProperty("file.separator"));
  172. }
  173. }
  174. /**
  175. * Sanitise a string to be used as a filename.
  176. *
  177. * @param name String to sanitise
  178. *
  179. * @return Sanitised version of name that can be used as a filename.
  180. */
  181. protected static String sanitise(final String name) {
  182. // Replace illegal chars with
  183. return name.replaceAll("[^\\w\\.\\s\\-#&_]", "_");
  184. }
  185. /**
  186. * Get the md5 hash of a string.
  187. *
  188. * @param string String to hash
  189. *
  190. * @return md5 hash of given string
  191. */
  192. protected static String md5(final String string) {
  193. try {
  194. final MessageDigest m = MessageDigest.getInstance("MD5");
  195. m.update(string.getBytes(), 0, string.length());
  196. return new BigInteger(1, m.digest()).toString(16);
  197. } catch (NoSuchAlgorithmException e) {
  198. return "";
  199. }
  200. }
  201. }