{"id":8348,"date":"2017-02-28T12:45:12","date_gmt":"2017-02-28T18:45:12","guid":{"rendered":"https:\/\/stackify.com\/?p=8348"},"modified":"2024-05-22T05:18:13","modified_gmt":"2024-05-22T05:18:13","slug":"java-logging-best-practices","status":"publish","type":"post","link":"https:\/\/stackify.com\/java-logging-best-practices\/","title":{"rendered":"Java Best Practices for Smarter Application Logging &#038; Exception Handling"},"content":{"rendered":"<h2><strong>Logging: We Should be Doing This Better by Now!<\/strong><\/h2>\n<p>What do I mean? There are lots of Java logging frameworks and libraries out there, and most developers use one or more of them every day. Two of the most common examples for Java developers are log4j and logback. They are simple and easy to use and work great for developers. Basic java log files are\u00a0just not enough, though, but we have some Java best practices and tips to help you make the most of them!<\/p>\n<p>Have you ever had to work with your <a href=\"https:\/\/stackify.com\/java-logs-types\/\">log files<\/a> once your application left development? If so, you quickly run into a few pain points.<\/p>\n<ul>\n<li>There\u2019s a lot more data.<\/li>\n<li>You have to get access to the data.<\/li>\n<li>It\u2019s <strong>spread across multiple servers.<\/strong><\/li>\n<li>A specific operation may be spread across applications\u00a0\u2013 so even more logs to dig through.<\/li>\n<li>It\u2019s flat and hard to query; even if you do put it in SQL, you are going to have to do full-text\u00a0indexing to make it usable.<\/li>\n<li>It\u2019s hard to read; messages are scrambled like spaghetti.<\/li>\n<li>You generally don\u2019t have any context of the user, etc.<\/li>\n<li>You probably lack some details that would be helpful. (You mean \u201clog.Info(\u2018In the method\u2019)\u201d isn\u2019t helpful???)<\/li>\n<li>You will be managing log file rotation and retention.<\/li>\n<\/ul>\n<p>Additionally, you have all this rich data about your app that is being generated and you simply aren\u2019t <em>proactively putting it to work<\/em>.<\/p>\n<h2><a id=\"post-8348-_v0iln7t91ge2\"><\/a><strong>It\u2019s Time to Get Serious About Logging<\/strong><\/h2>\n<p>Once you\u2019re working on an application that is not running on your desktop, logging messages (including exceptions) are usually your only lifeline to <em>quickly <\/em>discovering why something in your app isn\u2019t working correctly. Sure, <a href=\"https:\/\/stackify.com\/application-performance-management-tools\/\">APM tools<\/a> can alert you to <a href=\"\/memory-leaks-java\/\">memory leaks<\/a> and performance bottlenecks, but generally lack enough detail to help you solve a specific problem, i.e. why can\u2019t <em>this<\/em> user log in, or why isn\u2019t <em>this <\/em>record processing?<\/p>\n<p>At Stackify, we\u2019ve built a \u201cculture of logging\u201d which set out to accomplish these goals:<\/p>\n<ol>\n<li><strong>Log all the things.<\/strong> Log as much as we possibly can, to always have relevant, contextual logs that don\u2019t add overhead.<\/li>\n<li><strong>Work smarter, not harder.<\/strong> Consolidate and <a href=\"https:\/\/stackify.com\/log-management\/\">aggregate all of our logging<\/a> to a central location, available to all devs, and <em>easy to distil<\/em>. Also, to find new ways for our logging and exception data to help us <em>proactively <\/em>improve our product.<\/li>\n<\/ol>\n<p><span id=\"hs-cta-wrapper-3b34b9d8-23e4-49f5-b8fe-4040e86faae0\" class=\"hs-cta-wrapper\"><span id=\"hs-cta-3b34b9d8-23e4-49f5-b8fe-4040e86faae0\" class=\"hs-cta-node hs-cta-3b34b9d8-23e4-49f5-b8fe-4040e86faae0\"><br \/>\n<a href=\"http:\/\/cta-redirect.hubspot.com\/cta\/redirect\/207384\/3b34b9d8-23e4-49f5-b8fe-4040e86faae0\"><img loading=\"lazy\" decoding=\"async\" id=\"hs-cta-img-3b34b9d8-23e4-49f5-b8fe-4040e86faae0\" class=\"hs-cta-img aligncenter\" style=\"border-width: 0px;\" src=\"https:\/\/no-cache.hubspot.com\/cta\/default\/207384\/3b34b9d8-23e4-49f5-b8fe-4040e86faae0.png\" alt=\"The 8 Tools Every Java Developer Needs. See Them Here.\" width=\"451\" height=\"49\" \/><\/a><\/span> <\/span><br \/>\n<!-- end HubSpot Call-to-Action Code --><\/p>\n<p>In this post, we\u2019ll explore these best practices, and share what we\u2019ve done to address it, much of which has become a part of Stackify\u2019s <a href=\"https:\/\/stackify.com\/log-management\/\">log management<\/a> product. Also, if you haven\u2019t used <a href=\"https:\/\/stackify.com\/best-log-viewer-prefix\/\">Prefix to view your logs<\/a>, be sure to check it out!<\/p>\n<h2><a id=\"post-8348-_mu5c835aulr1\"><\/a><strong>Start<\/strong>\u00a0<strong>Logging All the Things!<\/strong><\/h2>\n<p>I\u2019ve worked in a lot of shops where log messages looked like this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8349\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8349-catch.png\" alt=\"catch exception\" width=\"509\" height=\"106\" \/><\/p>\n<p>I\u2019ll give the developer credit; at least they are using a try\/catch and handling the exception. The exception will likely have a stack trace so I know roughly where it came from, but <strong>no other context <\/strong>is logged.<\/p>\n<p>Sometimes, they even do some more proactive logging, like this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8350\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8350-logger-debug.png\" alt=\"public void process results\" width=\"711\" height=\"100\" \/><\/p>\n<p>But generally, statements like that don\u2019t go a long way towards letting you know what\u2019s really happening in your app. If you\u2019re tasked with troubleshooting an error in production, and\/or it is happening for just one (or a subset) of the application users, this doesn\u2019t leave you with a lot to go on, especially when considering your log statement could be a needle in a haystack in an app with lots of use.<\/p>\n<p>As I mentioned earlier, logging is often one of the few lifelines you have in production environments where you can\u2019t physically attach and debug. You want to log as much relevant, contextual data as you can. Here are our guiding principles on doing that.<\/p>\n<h2><a id=\"post-8348-_9gz1pyayvbv2\"><\/a><strong>Walk the Code<\/strong><\/h2>\n<p>Let&#8217;s pretend that\u00a0you have a process that you want to add logging around so that you can look at what happened. You <em>could<\/em> just put a try \/ catch around the entire thing and handle the exceptions (which you should) but it doesn\u2019t tell you much about <strong>what was passed\u00a0<em>into <\/em>the request<\/strong>. Take a look at the following, oversimplified example.<\/p>\n<pre class=\"prettyprint\">public class Foo {\n\n    private int id;\n       \n    private double value;\n    \n    public Foo(int id, double value) {\n   \t this.id = id;\n   \t this.value = value;\n    }\n    \n    public int getId() {\n   \t return id;\n    }\n\n    public double getValue() {\n   \t return value;\n    }\n    \n}\n<\/pre>\n<p>Take the following <a href=\"\/static-factory-methods\/\">factory method<\/a>, which creates a Foo. Note how I\u2019ve opened the door for error \u2013 the method takes a Double as an input parameter. I call doubleValue() but don\u2019t check for null. This could cause an exception.<\/p>\n<pre class=\"prettyprint\">public class FooFactory {\n\n    public static Foo createFoo(int id, Double value) {\n   \t return new Foo(id, value.doubleValue());\n    }\n    \n}\n<\/pre>\n<p>This is a simple\u00a0scenario, but it serves the purpose well. Assuming this is a really critical aspect of my Java app (can\u2019t have any failed Foos!) let\u2019s add some basic logging so we know what\u2019s going on.<\/p>\n<pre class=\"prettyprint\">public class FooFactory {\n\n    private static Logger LOGGER = LoggerFactory.getLogger(FooFactory.class);\n    \n    public static Foo createFoo(int id, Double value) {\n   \t \n   \t LOGGER.debug(\"Creating a Foo\");\n   \t \n   \t try {\n   \t\t Foo foo = new Foo(id, value.doubleValue());\n   \t\t \n   \t\t LOGGER.debug(\"{}\", foo);\n   \t\t \n   \t\t return foo;\n   \t\t \n   \t } catch (Exception e) {\n   \t\t LOGGER.error(e.getMessage(), e);\n   \t }\n   \t \n   \t return null;\n    }\n    \n}\n<\/pre>\n<p>Now, let\u2019s create two\u00a0foos; one that is valid and one that is not:<\/p>\n<pre class=\"prettyprint\">    FooFactory.createFoo(1, Double.valueOf(33.0));\n    FooFactory.createFoo(2, null);\n<\/pre>\n<p>And now we can see\u00a0some logging, and it looks like this:<\/p>\n<pre class=\"prettyprint\">2017-02-15 17:01:04,842 [main] DEBUG com.stackifytest.logging.FooFactory: Creating a Foo\n2017-02-15 17:01:04,848 [main] DEBUG com.stackifytest.logging.FooFactory: com.stackifytest.logging.Foo@5d22bbb7\n2017-02-15 17:01:04,849 [main] DEBUG com.stackifytest.logging.FooFactory: Creating a Foo\n2017-02-15 17:01:04,851 [main] ERROR com.stackifytest.logging.FooFactory:\njava.lang.NullPointerException\n    at com.stackifytest.logging.FooFactory.createFoo(FooFactory.java:15)\n    at com.stackifytest.logging.FooFactoryTest.test(FooFactoryTest.java:11)\n<\/pre>\n<p>Now we have some logging \u2013 we know when Foo objects are created, and when they fail to create in createFoo(). But we are missing some context that would help. The default toString() implementation doesn\u2019t build any data about the members of the object. We have some options here, but let\u2019s have the <a href=\"\/top-integrated-developer-environments-ides\/\">IDE<\/a> generate an implementation for us.<\/p>\n<pre class=\"prettyprint\">    @Override\n    public String toString() {\n   \t return \"Foo [id=\" + id + \", value=\" + value + \"]\";\n    }\n<\/pre>\n<p>Run our test again:<\/p>\n<pre class=\"prettyprint\">2017-02-15 17:13:06,032 [main] DEBUG com.stackifytest.logging.FooFactory: Creating a Foo\n2017-02-15 17:13:06,041 [main] DEBUG com.stackifytest.logging.FooFactory: Foo [id=1, value=33.0]\n2017-02-15 17:13:06,041 [main] DEBUG com.stackifytest.logging.FooFactory: Creating a Foo\n2017-02-15 17:13:06,043 [main] ERROR com.stackifytest.logging.FooFactory:\njava.lang.NullPointerException\n    at com.stackifytest.logging.FooFactory.createFoo(FooFactory.java:15)\n    at com.stackifytest.logging.FooFactoryTest.test(FooFactoryTest.java:11)\n<\/pre>\n<p><strong>Much better!<\/strong> Now we can see the object that was logged as &#8220;[id=, value=]&#8221;. Another option you have for toString is to use Javas&#8217; reflection capabilities. The main benefit here is that you don\u2019t have to modify the toString method when you add or remove members. Here is an example using Google\u2019s Gson library. Now, let\u2019s look at the output:<\/p>\n<pre class=\"prettyprint\">2017-02-15 17:22:55,584 [main] DEBUG com.stackifytest.logging.FooFactory: Creating a Foo\n2017-02-15 17:22:55,751 [main] DEBUG com.stackifytest.logging.FooFactory: {\"id\":1,\"value\":33.0}\n2017-02-15 17:22:55,754 [main] DEBUG com.stackifytest.logging.FooFactory: Creating a Foo\n2017-02-15 17:22:55,760 [main] ERROR com.stackifytest.logging.FooFactory:\njava.lang.NullPointerException\n    at com.stackifytest.logging.FooFactory.createFoo(FooFactory.java:15)\n    at com.stackifytest.logging.FooFactoryTest.test(FooFactoryTest.java:11)\n<\/pre>\n<p>When you log objects as JSON and use Stackify\u2019s Retrace tool, you can get some nice details like this:<\/p>\n<figure id=\"attachment_8351\" aria-describedby=\"caption-attachment-8351\" style=\"width: 875px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-8351 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8351-json-view-e1488513845866.png\" alt=\"eric-ubuntu\" width=\"875\" height=\"362\" \/><figcaption id=\"caption-attachment-8351\" class=\"wp-caption-text\">Retrace Logging Dashboard JSON Viewer<\/figcaption><\/figure>\n<h2><a id=\"post-8348-_h7x045z4az0v\"><\/a><strong>Logging More Details with Diagnostic Contexts<\/strong><\/h2>\n<p>And this brings us to one last point on logging more details: diagnostic context logging. When it comes to debugging a production issue, you might have the \u201cCreating a Foo\u201d message thousands of times in your logs, but with no clue who the logged in user was that created it. Know who the user was\u00a0is the sort of context that is priceless in being able to quickly resolve an issue. Think about what other detail might be useful \u2013 for example, HttpWebRequest details. But who wants to have to remember to log it every time? Diagnostic context logging to the rescue, specifically the mapped diagnostic context. Read more about SLF4J\u2019s MDC here: <a href=\"https:\/\/logback.qos.ch\/manual\/mdc.html\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/logback.qos.ch\/manual\/mdc.html<\/a>.<\/p>\n<p>The easiest way to add context items to your logging is usually a servlet filter. For this example, let\u2019s create a servlet filter that generates a transaction id and attaches it to the MDC.<\/p>\n<pre class=\"prettyprint\">public class LogContextFilter implements Filter {\n\n    public void init(FilterConfig config) {\n    }\n    \n    public void destroy() {\n    }\n\n    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {\n   \t \n   \t String transactionId = UUID.randomUUID().toString();\n   \t \n   \t MDC.put(\"TRANS_ID\", transactionId);\n   \t \n   \t try {\n   \t\t chain.doFilter(request, response);\n   \t }\n   \t finally {\n   \t\t MDC.clear();\n   \t }\n    }\n\n}\n<\/pre>\n<p>Now, we can see some log statements like this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8352 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8352-e1488513883492.png\" alt=\"image\" width=\"875\" height=\"49\" \/><\/p>\n<p>More context. We can now trace all log statements from a single request.<\/p>\n<p>This brings us to the next topic, which is <strong>Work Harder, Not Smarter.<\/strong> But before that, I\u2019m going to address a question I\u2019m sure to hear a lot of in the comments: \u201cBut if I log <em>everything<\/em> won\u2019t that create overhead, unnecessary chatter, and huge log files?\u201d My answer comes in a couple of parts: first, use the logging verbosity levels. you can <em>LOGGER.debug()<\/em> <strong>everything you think you\u2019ll need<\/strong>, and then set your config for production appropriately, i.e. Warning and above only. When you do need the debug info, it\u2019s only changing a config file and not redeploying code. Second, if you\u2019re logging in an <em>async, non-blocking way<\/em>, then overhead should be low. Last, if you\u2019re worried about space and log file rotation, there are smarter ways to do it, and we\u2019ll talk about that in the next section.<\/p>\n<h2><a id=\"post-8348-_x6a2n99ysb5j\"><\/a><strong>Work Smarter, Not Harder<\/strong><\/h2>\n<p>Now that we\u2019re logging <em>everything<\/em>, and it\u2019s providing more\u00a0contextual data, we\u2019re going to look at the next part of the equation. As I\u2019ve mentioned, and demonstrated, just dumping all of this out to flat files still doesn\u2019t help you out a lot in a large, complex application and environment. Factor in thousands of requests, files spanning multiple days, weeks, or longer, and across multiple servers, you have to consider how you are going to quickly find the data that you need.<\/p>\n<p>What we all really need is a solution that provides:<\/p>\n<ul>\n<li>Aggregates all Log &amp; Exception data to one place<\/li>\n<li>Makes it available, instantly, to everyone on your team<\/li>\n<li>Presents a timeline of logging throughout your entire stack\/infrastructure<\/li>\n<li>Is highly indexed and searchable\u00a0by being in a\u00a0<a href=\"https:\/\/stackify.com\/what-is-structured-logging-and-why-developers-need-it\/\">structured format<\/a><\/li>\n<\/ul>\n<p>This is the part where I tell you about <a href=\"\/retrace\/\">Stackify Retrace<\/a>. As we sought to improve our own abilities to quickly and efficiently work with our log data, we decided to make it a core part of our product (yes, we use Stackify to monitor Stackify) and share with our customers, since we believe it\u2019s an issue central to application troubleshooting.<\/p>\n<p>First, we realize that lots of developers already have logging in place, and aren\u2019t going to want to take a lot of time to rip that code out and put new code in. That\u2019s why we\u2019ve created logging appenders for the most common Java logging frameworks.<\/p>\n<ul>\n<li>log4j 1.2 (<a href=\"https:\/\/github.com\/stackify\/stackify-log-log4j12\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/github.com\/stackify\/stackify-log-log4j12<\/a>)<\/li>\n<li>log4j 2.x (<a href=\"https:\/\/github.com\/stackify\/stackify-log-log4j2\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/github.com\/stackify\/stackify-log-log4j2<\/a>)<\/li>\n<li>logback (<a href=\"https:\/\/github.com\/stackify\/stackify-log-logback\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/github.com\/stackify\/stackify-log-logback<\/a>)<\/li>\n<\/ul>\n<p>Continuing with log4j as a sample, the setup is easy. Just add the Stackify appender to your project\u2019s maven pom file.<\/p>\n<pre class=\"prettyprint\">&lt;dependency&gt;\n   &lt;groupId&gt;com.stackify&lt;\/groupId&gt;\n   &lt;artifactId&gt;stackify-log-log4j12&lt;\/artifactId&gt;\n   &lt;version&gt;1.1.9&lt;\/version&gt;\n   &lt;scope&gt;runtime&lt;\/scope&gt;\n&lt;\/dependency&gt;\n<\/pre>\n<p>Also, add in some configuration for the Stackify appender to your logging.properties file.<\/p>\n<pre class=\"prettyprint\">log4j.rootLogger=DEBUG, CONSOLE, STACKIFY\n\nlog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender\n\nlog4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.CONSOLE.layout.ConversionPattern=%d [%t] %-5p %c: %m%n\n\nlog4j.appender.STACKIFY=com.stackify.log.log4j12.StackifyLogAppender\nlog4j.appender.STACKIFY.apiKey=[HIDDEN]\nlog4j.appender.STACKIFY.application=test-logging\nlog4j.appender.STACKIFY.environment=test\n<\/pre>\n<p>As you can see, if you\u2019re already using a different appender, you can keep it in place and put them side-by-side. Now that you\u2019ve got your logs streaming to Stackify we can take a look at the logging dashboard.\u00a0(By the way, if our monitoring agent is installed, you can also send <a href=\"\/syslog-101\/\">Syslog<\/a> entries to Stackify as well!)<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8353 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8353-e1488513909777.png\" alt=\"retrace\" width=\"875\" height=\"384\" \/><\/p>\n<p>This dashboard shows a consolidated stream of log data, coming from all your servers and apps, presented in a timeline. From here, you can quickly<\/p>\n<ul>\n<li>View logs based on a range of time<\/li>\n<li>Filter for specific servers, apps, or environments<\/li>\n<\/ul>\n<p>Plus there are a couple of really great usability things built in. One of the first things you\u2019ll notice is that chart at the top. It\u2019s a great way to quickly \u201ctriage\u201d your application. The blue line indicates the rate of log messages, and the red bars indicate # of <a href=\"\/best-practices-exceptions-java\/\">exceptions being logged<\/a>.<\/p>\n<p>It\u2019s clear that a few minutes ago, my web app started having a lot more consistent activity but more importantly, we started getting more exceptions about the same time. Exceptions don\u2019t come without overhead for your CPU and memory, and they also can have a direct impact on user satisfaction, which can cost real money.<\/p>\n<p>By zooming in on the chart to this time period, I can quickly filter my log detail down to that time range and take a look at the logs for that period of time.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8354 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8354-e1488513935832.png\" alt=\"retrace\" width=\"875\" height=\"373\" \/><\/p>\n<h2><a id=\"post-8348-_6ucg07t4iaji\"><\/a><strong>Searching Your Logs<\/strong><\/h2>\n<p>Do you see that blue text below that looks like a JSON\u00a0object?<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8355 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8355-e1488513956939.png\" alt=\"retrace\" width=\"875\" height=\"279\" \/><\/p>\n<p>Well, it <em>is<\/em> a JSON\u00a0object. That\u2019s the result of logging objects, and adding context properties earlier. It looks a lot nicer than plain text in a flat file, doesn\u2019t it? Well, it gets even more awesome. See the search box at the top of the page? I can put in any search string that I can think of, and it will <strong>query all my logs as if it were a flat file<\/strong>. As we discussed earlier, however, this isn\u2019t <em>great <\/em>because you could end up with a lot more matches than you want. Suppose that I want to search for all objects with an id of 5. Fortunately, our log aggregator is smart enough to help in this situation. That\u2019s because when we find serialized objects in logs, we index each and every field we find. That makes it easy to perform a search like this:<\/p>\n<pre class=\"prettyprint\">json.idNumber:5.0\n<\/pre>\n<p>That search yields the following results:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8356 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8356-e1488514288367.png\" alt=\"retrace image\" width=\"875\" height=\"252\" \/><\/p>\n<p>Want to know what else you can search by? Just click on the document icon when you hover over a log record, and you\u2019ll see all the fields that Stackify indexes. Being able to get more value out of your logs and search by all the fields is called <a href=\"https:\/\/stackify.com\/what-is-structured-logging-and-why-developers-need-it\/\">structured logging<\/a>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8357 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8357-e1488514247566.png\" alt=\"retrace image\" width=\"875\" height=\"363\" \/><\/p>\n<h2><a id=\"post-8348-_9a9o0f94km7y\"><\/a>Exploring Java\u00a0<strong>Exception Details<\/strong><\/h2>\n<p>You may have also noticed this little red bug icon\u00a0(<img decoding=\"async\" class=\"wp-image-8358\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/bug.png\" alt=\"bug\" \/>) next to exception messages. That\u2019s because we treat exceptions differently by automatically showing more context. Click on it and we present a deeper view of that exception.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8359 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8359-e1488514228520.png\" alt=\"error detail\" width=\"875\" height=\"394\" \/><\/p>\n<p>Our libraries not only grab the full stack trace, but all of the web request details, including headers, query strings, and server variables, when available. In this modal, there is a \u201cLogs\u201d tab which gives you a pre-filtered view of the logging from the app that threw the error, on the server where it occurred, for a narrow time window before and after the exception, to give more context around the exception. Curious about how common or frequent this error occurs, or want to see details on other occurrences? Click the \u201cView All Occurrences\u201d button and voila!<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8360 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8360-e1488514203357.png\" alt=\"retrace\" width=\"875\" height=\"416\" \/><\/p>\n<p>I can quickly see this error has occurred 60 times over the last hour. Errors and logs are closely related, and in an app where a tremendous amount of logging can occur, exceptions could sometimes get a bit lost in the noise. That\u2019s why we\u2019ve built an <a href=\"https:\/\/stackify.com\/error-monitoring\/\">Errors Dashboard<\/a> as well, to give you this same consolidated view but limited to exceptions.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8361 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8361-e1488514180766.png\" alt=\"retrace\" width=\"875\" height=\"446\" \/><\/p>\n<p>Here I can see a couple of great pieces of data:<\/p>\n<ul>\n<li>I\u2019ve had an uptick in my rate of exceptions over the past few minutes.<\/li>\n<li>The majority of my errors are coming from my \u201ctest\u201d environment \u2013 to the tune of about 84 per hour.<\/li>\n<li>I have a couple of new errors that have just started occurring (as indicated by the red triangles).<\/li>\n<\/ul>\n<p>Have you ever put a new release of your app out to production and wondered what QA missed? (Not that I\u2019m saying QA would ever miss a bug\u2026\u2026) Error Dashboard to the rescue. You can watch real time and see a trend \u2013 lots of red triangles, lots of new bugs. Big spike in the graph? Perhaps you have an increase in usage, so a previously known error is being hit more; perhaps some buggy code (like a leaking SQL connection pool) went out and is causing a higher rate of SQL timeout errors than normal.<\/p>\n<p>It\u2019s not hard to imagine a lot of different scenarios for which this could provide early warning and detection. Hmm. Early warning and detection. That brings up another great topic.<\/p>\n<h2><a id=\"post-8348-_shvll0hb4e9r\"><\/a>Monitor<\/h2>\n<p>Wouldn\u2019t it be nice to be alerted when<\/p>\n<ul>\n<li>An error rate for a specific app or environment suddenly increases?<\/li>\n<li>An error that was specifically resolved starts happening again?<\/li>\n<li>A certain action that you log does not happen enough, too often, etc?<\/li>\n<\/ul>\n<p>Stackify can do all of that. Let\u2019s take a look at each.<\/p>\n<h2><a id=\"post-8348-_tglsn5gpke95\"><\/a>Error Rates<\/h2>\n<p>When we looked at the error dashboard, I noted that my \u2018test\u2019 environment is getting a high number of errors per hour. From the Error dashboard, click on \u201cError Rates\u201d and then select which app\/environment you wish to configure alerts for:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8362 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8362-e1488514150613.png\" alt=\"configure app monitoring\" width=\"875\" height=\"447\" \/><\/p>\n<p>I can configure monitors for \u201cErrors\/Minute\u201d and \u201cTotal Errors Last 60 minutes\u201d and then choose the \u201cNotifications\u201d tab to specify who should be alerted, and how. Subsequently, if using Stackify Monitoring, I can configure all of my other alerting here as well: App running state, memory usage, performance counters, custom metrics, ping checks, and more.<\/p>\n<h3><a id=\"post-8348-_khwszkqylcmu\"><\/a><strong>Resolved Errors &amp; New Errors<\/strong><\/h3>\n<p>Earlier on, I introduced a new error by not checking for null values when creating Foo objects. I\u2019ve since fixed that and confirmed it by looking at the details for that particular error. As you can see, the last time it happened was 12 minutes ago:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8363 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8363-e1488514130602.png\" alt=\"retrace image\" width=\"875\" height=\"338\" \/><\/p>\n<p>It was a silly mistake, but one that is easy to make. I\u2019m going to mark this one as \u201cresolved\u201d which lets me do something really cool: get an alert if it comes back. The Notifications menu will let me check my configuration, and by default, I\u2019m set to receive both new and regressed error notifications for all my apps and environments.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8364 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8364-e1488514110935.png\" alt=\"error notification\" width=\"875\" height=\"151\" \/><\/p>\n<p>Now, if the same error occurs again in the future, I\u2019m going to get an email about the regression and it shows up on the dashboard as such. This is a great little bit of automation to help out when you \u201cthink\u201d you\u2019ve solved the issue and want to make sure.<\/p>\n<h3><a id=\"post-8348-_1p94amhzq76w\"><\/a><strong>Log Monitors<\/strong><\/h3>\n<p>Some things aren\u2019t very straightforward to monitor. Perhaps you have a critical process that runs asynchronously and the only record of its success (or failure) is logging statements. Earlier in this post, I showed the ability to run deep queries against your <a href=\"https:\/\/stackify.com\/what-is-structured-logging-and-why-developers-need-it\/\">structured log data<\/a>, and any of those queries can be saved and monitored. I\u2019ve got a very simple scenario here: my query is executed every minute, and we can monitor how many matching records we have.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8365 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8365-e1488514090350.png\" alt=\"log monitor\" width=\"875\" height=\"431\" \/><\/p>\n<p>It\u2019s just a great simple way to check system health if a log file is your only indication.<\/p>\n<h2><strong>Java Logging Best Practices<\/strong><\/h2>\n<p>All of this error and log data can be invaluable, especially when you take a step back and look at a slightly larger picture. Below is the Application Dashboard for a Java web app that contains all of the monitoring:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8366 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8366-e1488514025858.png\" alt=\"dashboard\" width=\"875\" height=\"344\" \/><\/p>\n<p>As you can see, you get some great contextual data at a glance that errors and logs contribute to: Satisfaction and HTTP Error Rate. You can see that user satisfaction is high and the HTTP error rate is low. You can quickly start drilling down to see which pages might not be performing well, and what errors are occurring:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8367 size-full\" src=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logging-best-practices-8367-e1488514002335.png\" alt=\"monitoring dashboard\" width=\"875\" height=\"448\" \/><\/p>\n<p>There was a lot to cover in this post, and I feel like I barely scratched the surface. If you dig a little deeper or even get your hands on it, you can! I hope that these Java logging best practices will help you write better logs and save time troubleshooting.<\/p>\n<p>All of our Java logging appenders are available on <a href=\"https:\/\/github.com\/stackify\" target=\"_blank\" rel=\"noopener noreferrer\">GitHub<\/a> and you can\u00a0<a href=\"https:\/\/stackify.com\/free-trial\/\">sign up for a free trial<\/a> to get started with Stackify today!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Logging: We Should be Doing This Better by Now! What do I mean? There are lots of Java logging frameworks and libraries out there, and most developers use one or more of them every day. Two of the most common examples for Java developers are log4j and logback. They are simple and easy to use [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":38532,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7],"tags":[40,26],"class_list":["post-8348","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-developers","tag-java","tag-logging"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v25.6) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Java Logging Best Practices: How to Get More Out of Your Log Data<\/title>\n<meta name=\"description\" content=\"There are lots of Java logging frameworks and libraries out there, the most common are log4j and logback. Get best practices to make the most of them!\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/stackify.com\/java-logging-best-practices\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Java Logging Best Practices: How to Get More Out of Your Log Data\" \/>\n<meta property=\"og:description\" content=\"There are lots of Java logging frameworks and libraries out there, the most common are log4j and logback. Get best practices to make the most of them!\" \/>\n<meta property=\"og:url\" content=\"https:\/\/stackify.com\/java-logging-best-practices\/\" \/>\n<meta property=\"og:site_name\" content=\"Stackify\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Stackify\/\" \/>\n<meta property=\"article:published_time\" content=\"2017-02-28T18:45:12+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-05-22T05:18:13+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logs-stk-881x441-1.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"881\" \/>\n\t<meta property=\"og:image:height\" content=\"441\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Alexandra Altvater\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@stackify\" \/>\n<meta name=\"twitter:site\" content=\"@stackify\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Alexandra Altvater\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"18 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/stackify.com\/java-logging-best-practices\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/stackify.com\/java-logging-best-practices\/\"},\"author\":{\"name\":\"Alexandra Altvater\",\"@id\":\"https:\/\/stackify.com\/#\/schema\/person\/3087594560b933be18c662a37d09b51a\"},\"headline\":\"Java Best Practices for Smarter Application Logging &#038; Exception Handling\",\"datePublished\":\"2017-02-28T18:45:12+00:00\",\"dateModified\":\"2024-05-22T05:18:13+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/stackify.com\/java-logging-best-practices\/\"},\"wordCount\":3099,\"publisher\":{\"@id\":\"https:\/\/stackify.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/stackify.com\/java-logging-best-practices\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logs-stk-881x441-1.jpg\",\"keywords\":[\"Java\",\"logging\"],\"articleSection\":[\"Developer Tips, Tricks &amp; Resources\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/stackify.com\/java-logging-best-practices\/\",\"url\":\"https:\/\/stackify.com\/java-logging-best-practices\/\",\"name\":\"Java Logging Best Practices: How to Get More Out of Your Log Data\",\"isPartOf\":{\"@id\":\"https:\/\/stackify.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/stackify.com\/java-logging-best-practices\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/stackify.com\/java-logging-best-practices\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logs-stk-881x441-1.jpg\",\"datePublished\":\"2017-02-28T18:45:12+00:00\",\"dateModified\":\"2024-05-22T05:18:13+00:00\",\"description\":\"There are lots of Java logging frameworks and libraries out there, the most common are log4j and logback. Get best practices to make the most of them!\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/stackify.com\/java-logging-best-practices\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/stackify.com\/java-logging-best-practices\/#primaryimage\",\"url\":\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logs-stk-881x441-1.jpg\",\"contentUrl\":\"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logs-stk-881x441-1.jpg\",\"width\":881,\"height\":441},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/stackify.com\/#website\",\"url\":\"https:\/\/stackify.com\/\",\"name\":\"Stackify\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/stackify.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/stackify.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/stackify.com\/#organization\",\"name\":\"Stackify\",\"url\":\"https:\/\/stackify.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/stackify.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/stackify.com\/wp-content\/uploads\/2024\/05\/logo-1.png\",\"contentUrl\":\"https:\/\/stackify.com\/wp-content\/uploads\/2024\/05\/logo-1.png\",\"width\":1377,\"height\":430,\"caption\":\"Stackify\"},\"image\":{\"@id\":\"https:\/\/stackify.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/Stackify\/\",\"https:\/\/x.com\/stackify\",\"https:\/\/www.instagram.com\/stackify\/\",\"https:\/\/www.linkedin.com\/company\/2596184\",\"https:\/\/www.youtube.com\/stackify\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/stackify.com\/#\/schema\/person\/3087594560b933be18c662a37d09b51a\",\"name\":\"Alexandra Altvater\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/stackify.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/99e0459a6d11f4f510127934dfd98b94?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/99e0459a6d11f4f510127934dfd98b94?s=96&d=mm&r=g\",\"caption\":\"Alexandra Altvater\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Java Logging Best Practices: How to Get More Out of Your Log Data","description":"There are lots of Java logging frameworks and libraries out there, the most common are log4j and logback. Get best practices to make the most of them!","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/stackify.com\/java-logging-best-practices\/","og_locale":"en_US","og_type":"article","og_title":"Java Logging Best Practices: How to Get More Out of Your Log Data","og_description":"There are lots of Java logging frameworks and libraries out there, the most common are log4j and logback. Get best practices to make the most of them!","og_url":"https:\/\/stackify.com\/java-logging-best-practices\/","og_site_name":"Stackify","article_publisher":"https:\/\/www.facebook.com\/Stackify\/","article_published_time":"2017-02-28T18:45:12+00:00","article_modified_time":"2024-05-22T05:18:13+00:00","og_image":[{"width":881,"height":441,"url":"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logs-stk-881x441-1.jpg","type":"image\/jpeg"}],"author":"Alexandra Altvater","twitter_card":"summary_large_image","twitter_creator":"@stackify","twitter_site":"@stackify","twitter_misc":{"Written by":"Alexandra Altvater","Est. reading time":"18 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/stackify.com\/java-logging-best-practices\/#article","isPartOf":{"@id":"https:\/\/stackify.com\/java-logging-best-practices\/"},"author":{"name":"Alexandra Altvater","@id":"https:\/\/stackify.com\/#\/schema\/person\/3087594560b933be18c662a37d09b51a"},"headline":"Java Best Practices for Smarter Application Logging &#038; Exception Handling","datePublished":"2017-02-28T18:45:12+00:00","dateModified":"2024-05-22T05:18:13+00:00","mainEntityOfPage":{"@id":"https:\/\/stackify.com\/java-logging-best-practices\/"},"wordCount":3099,"publisher":{"@id":"https:\/\/stackify.com\/#organization"},"image":{"@id":"https:\/\/stackify.com\/java-logging-best-practices\/#primaryimage"},"thumbnailUrl":"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logs-stk-881x441-1.jpg","keywords":["Java","logging"],"articleSection":["Developer Tips, Tricks &amp; Resources"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/stackify.com\/java-logging-best-practices\/","url":"https:\/\/stackify.com\/java-logging-best-practices\/","name":"Java Logging Best Practices: How to Get More Out of Your Log Data","isPartOf":{"@id":"https:\/\/stackify.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/stackify.com\/java-logging-best-practices\/#primaryimage"},"image":{"@id":"https:\/\/stackify.com\/java-logging-best-practices\/#primaryimage"},"thumbnailUrl":"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logs-stk-881x441-1.jpg","datePublished":"2017-02-28T18:45:12+00:00","dateModified":"2024-05-22T05:18:13+00:00","description":"There are lots of Java logging frameworks and libraries out there, the most common are log4j and logback. Get best practices to make the most of them!","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/stackify.com\/java-logging-best-practices\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/stackify.com\/java-logging-best-practices\/#primaryimage","url":"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logs-stk-881x441-1.jpg","contentUrl":"https:\/\/stackify.com\/wp-content\/uploads\/2017\/02\/java-logs-stk-881x441-1.jpg","width":881,"height":441},{"@type":"WebSite","@id":"https:\/\/stackify.com\/#website","url":"https:\/\/stackify.com\/","name":"Stackify","description":"","publisher":{"@id":"https:\/\/stackify.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/stackify.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/stackify.com\/#organization","name":"Stackify","url":"https:\/\/stackify.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/stackify.com\/#\/schema\/logo\/image\/","url":"https:\/\/stackify.com\/wp-content\/uploads\/2024\/05\/logo-1.png","contentUrl":"https:\/\/stackify.com\/wp-content\/uploads\/2024\/05\/logo-1.png","width":1377,"height":430,"caption":"Stackify"},"image":{"@id":"https:\/\/stackify.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Stackify\/","https:\/\/x.com\/stackify","https:\/\/www.instagram.com\/stackify\/","https:\/\/www.linkedin.com\/company\/2596184","https:\/\/www.youtube.com\/stackify"]},{"@type":"Person","@id":"https:\/\/stackify.com\/#\/schema\/person\/3087594560b933be18c662a37d09b51a","name":"Alexandra Altvater","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/stackify.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/99e0459a6d11f4f510127934dfd98b94?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/99e0459a6d11f4f510127934dfd98b94?s=96&d=mm&r=g","caption":"Alexandra Altvater"}}]}},"_links":{"self":[{"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/posts\/8348"}],"collection":[{"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/comments?post=8348"}],"version-history":[{"count":4,"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/posts\/8348\/revisions"}],"predecessor-version":[{"id":44166,"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/posts\/8348\/revisions\/44166"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/media\/38532"}],"wp:attachment":[{"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/media?parent=8348"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/categories?post=8348"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/stackify.com\/wp-json\/wp\/v2\/tags?post=8348"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}