{"id":416,"date":"2015-12-22T17:12:22","date_gmt":"2015-12-22T17:12:22","guid":{"rendered":"http:\/\/smartfoxserver.com\/blog\/?p=416"},"modified":"2015-12-22T17:12:22","modified_gmt":"2015-12-22T17:12:22","slug":"custom-logging-for-sfs2x-extensions","status":"publish","type":"post","link":"https:\/\/smartfoxserver.com\/blog\/custom-logging-for-sfs2x-extensions\/","title":{"rendered":"Custom logging for SFS2X Extensions"},"content":{"rendered":"<p>In this recipe we will take a look at how we can tweak\u00a0the logging configuration in SmartFoxServer 2X in order to do advanced logging from Extension code.<!--more--><\/p>\n<p>The standard SFS2X Extension API already provide a straightforward way of logging any data to the standard log files via the <strong>trace()<\/strong> command.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">trace(&quot;Hello from my Extension&quot;);<\/pre>\n<p>The result is this:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">09:16:16,584 INFO  [main] Extensions     - {MyExt}: Hello from my Extension<\/pre>\n<p>which can be broken down to:<\/p>\n<ul>\n<li><span style=\"color: #0000ff;\">09:16:16,584<\/span>\u00a0(time)<\/li>\n<li><span style=\"color: #0000ff;\">INFO<\/span> (log level)<\/li>\n<li><span style=\"color: #0000ff;\">[main]<\/span> (name of running thread)<\/li>\n<li><span style=\"color: #0000ff;\">Extensions<\/span> (logging category)<\/li>\n<li><span style=\"color: #0000ff;\">{MyExt}<\/span><\/li>\n<li><span style=\"color: #0000ff;\">Hello from my Extension<\/span> (the actual log message)<\/li>\n<\/ul>\n<p>In this recipe we&#8217;re going to customize the logging for our Extension by changing its format and isolating our logs in separate files. This way we&#8217;ll be able to investigate our game&#8217;s log without all the other messages generated by SmartFoxServer.<\/p>\n<h2>\u00bb Setting up Log4J<\/h2>\n<p><a title=\"Log4J\" href=\"http:\/\/logging.apache.org\/log4j\/2.x\/\" target=\"_blank\">Log4J<\/a> is a very popular logging library that has been around for over a decade and it is used\u00a0by SmartFoxServer via an abstraction layer called <a title=\"Simple Logging Facade for Java\" href=\"http:\/\/www.slf4j.org\/\" target=\"_blank\">SLF4J<\/a>.<\/p>\n<p>We can open its\u00a0configuration file, located under <strong>{SFS2X}\/config\/log4j.properties<\/strong>, with any text editor and add this block:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n# MyExt FileAppender\r\nlog4j.appender.myExtAppender=org.apache.log4j.DailyRollingFileAppender\r\nlog4j.appender.myExtAppender.layout=org.apache.log4j.PatternLayout\r\nlog4j.appender.myExtAppender.File=logs\/myExt\/myExt.log\r\nlog4j.appender.myExtAppender.layout.ConversionPattern=%d{dd MMM yyyy | HH:mm:ss,SSS} | %-5p | %t | %c{3} | %3x | %m%n\r\nlog4j.appender.myExtAppender.Encoding=UTF-8\r\nlog4j.appender.myExtAppender.DatePattern='.'yyyy-MM-dd\r\nlog4j.category.my.extension=INFO,myExtAppender\r\n<\/pre>\n<p>This section can be added right at the top of the file, below the initial comment lines which are denoted by a # (hashtag) sign.<\/p>\n<p>The <strong>log4j.appender.&lt;some-name&gt;<\/strong> declaration allows to define a custom appender (myExtAppender) which is configured to use the <em>DailyRollingFileAppender\u00a0<\/em>class from Log4J. This class rolls logs files on a daily basis, appending the current date to the tail of the log file name.<\/p>\n<p><strong>myExtAppender.File\u00a0<\/strong>configures the position and file name of our custom log files relative to the SmartFoxServer&#8217;s root folder.<\/p>\n<p><strong>myExtAppender.layout.ConversionPattern\u00a0<\/strong>declares the format of each logging line. This contains quite a lot of tokens that are useful to control which data and format we want to use when logging. You can learn all the details about pattern formats by consulting the\u00a0<a title=\"Log4J official doc\" href=\"https:\/\/logging.apache.org\/log4j\/1.2\/apidocs\/org\/apache\/log4j\/PatternLayout.html\" target=\"_blank\">official documentation<\/a>.<\/p>\n<p><strong>\u00a0myExtAppender.DatePattern\u00a0<\/strong>defines the date pattern discussed in the first section<\/p>\n<p>Finally\u00a0<strong>log4j.category.my.extension\u00a0<\/strong>declares a new Log4J category and sets its output to both the default <em>consoleAppender<\/em> and our custom <em>myExtAppender.<\/em><\/p>\n<p>A <strong>category<\/strong> in Log4J represents a package name, indicating that all classes having the same pattern in their package name will send their logs to the defined appenders. In other words this means that all classes under <strong>my.extension.*\u00a0<\/strong>package will send their log messages to <em>myExtAppender.<\/em><\/p>\n<h2>\u00bb\u00a0Using Log4J from Extension code<\/h2>\n<p>Now it is time to write some Extension code and see how we can use our newly customized logger.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n...\r\n...\r\n\r\npublic class MyGameExtension extends SFSExtension\r\n{\r\n\tprivate final Logger log = LoggerFactory.getLogger(MyGameExtension.class);\r\n\r\n\tpublic void init()\r\n\t{\r\n\t\tif (log.isDebugEnabled())\r\n\t\t\tlog.debug(&quot;This message will show only if in DEBUG mode.&quot;)\r\n\r\n\t\tlog.info(&quot;This is a regular INFO message&quot;);\r\n\r\n\t\tlog.warn(&quot;This is a WARN message, notifying an exception&quot;);\r\n\r\n\t\tlog.error(&quot;Bad news, an unrecoverable error just happened&quot;);\r\n\t}\r\n}\r\n<\/pre>\n<p>The code imports two classes from the SLF4J package, this is because we never work with our logging classes directly. Instead we use an abstraction which in turn allows to swap a number of logging implementations at runtime.<\/p>\n<p>Setting this aside, we obtain the <strong>log<\/strong> object via the <strong>LoggerFactory<\/strong> class and we can test it by logging different messages using\u00a0different log levels.<\/p>\n<p>Notice how we check for <strong>isDebugEnabled()<\/strong> before using the <strong>debug<\/strong> level, this is pretty important if you have lots of debugging messages in your Extension code. Debug level is recommended\u00a0for development and testing and should be turned off in production.<\/p>\n<p>In the previous configuration snippet we have this line:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">log4j.category.my.extension=INFO,consoleAppender,myExtAppender<\/pre>\n<p>where INFO can be replaced with DEBUG, WARN or ERROR, each defining the lowest level that allowed to generate output in the log files.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this recipe we will take a look at how we can tweak\u00a0the logging configuration in SmartFoxServer 2X in order to do advanced logging from Extension code.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[5],"tags":[31,36,7],"_links":{"self":[{"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts\/416"}],"collection":[{"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/comments?post=416"}],"version-history":[{"count":8,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts\/416\/revisions"}],"predecessor-version":[{"id":424,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts\/416\/revisions\/424"}],"wp:attachment":[{"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/media?parent=416"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/categories?post=416"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/tags?post=416"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}