Mostrando entradas con la etiqueta CheckStyle. Mostrar todas las entradas
Mostrando entradas con la etiqueta CheckStyle. Mostrar todas las entradas

miércoles, 14 de noviembre de 2018

Level up logs and ELK - Logging Cutting-Edge Practices - Documenting and sharing your most important logged information

 

Articles index:

  1. Introduction (Everyone)
  2. JSON as logs format (Everyone)
  3. Logging best practices with Logback (Targetting Java DEVs)
  4. Logging cutting-edge practices (Targetting Java DEVs) 
  5. Contract first log generator (Targetting Java DEVs)
  6. ElasticSearch VRR Estimation Strategy (Targetting OPS)
  7. VRR Java + Logback configuration (Targetting OPS)
  8. VRR FileBeat configuration (Targetting OPS)
  9. VRR Logstash configuration and Index templates (Targetting OPS)
  10. VRR Curator configuration (Targetting OPS)
  11. Logstash Grok, JSON Filter and JSON Input performance comparison (Targetting OPS)

Logging cutting-edge practices: Sharing your log strategy with other teams and departments



Once you have your ELK cluster in place, and your team is making an application (or several) logging into it, you still have a problem to solve.

Given either of the following scenarios:
  • A team newcomer is asked to investigate something that involves logs.
  • CTO has granted Support access to ELK so they can have some insights to application activity or problems.
  • Another team is investigating a cross-application problem.

Assuming they know the service, host and other common OPS-depending attributes...
  • What attributes can they query in ELK?
  • What to they mean?
  • What text does come with the data they need?
  • How do they know what data is correlated?

Bonus question
  • How do you enforce that same attribute has same name in all your logs? Moreover, how do you enforce it's always the same type?

I'll be proposing a number of different solutions in a iterative evolution, pick the one you prefer.

Baseline:


You are using  latest log format and best practices from Level up logs and ELK - Logging best practices with Logback
logger.info("New Market Status {} {}", kv("marketId", 1234), kv("newStatus", "ready"));

Cons:
  • Name or case could differ for same concept in different names.
  • Type mismatch is possible, same name, different type.
  • Enforcing usage as policy.
  • Not documentation available for sharing with other teams or for your own reference.

 

Iteration #1: Constant names


First problem to solve is ensuring we are not using different keys for the same concept.
Initially there's nothing that avoided this to happen:
logger.info("New Market Status {} {}", kv("marketId", 1234), kv("newStatus", "ready"));
[...] 
logger.info("Editing Market Status {} {}", kv("id", 1234), kv("newstatus", "ready"));

On one hand, no developer is going to manually check all the names for any variable to enforce consistency of names. On the other, even lower/upper case mismatch could ruin your queries as they are stored in case sensitive fields.

First iteration would make us think of a set of constant Strings or Enums to help us to deal with variety of names. Documentation about meaning, usage, required type and description could be explicit in comments.
public class LoggerUtils {
    public static final String MK_ID = "marketId"; //String - Market Id
    public static final String MK_NEW_STATUS = "newStatus"; //MarketStatus.java enum - New Market Status
}

Finally code would look like this (Enforced by code review and good will only)
logger.info("New Market Status {} {}", kv(MK_ID, 1234), kv(MK_NEW_STATUS, "ready"));
[...] 
logger.info("Editing Market Status {} {}", kv(MK_ID, 1234), kv(MK_NEW_STATUS, "ready"));

Cons:
  • Name or case could differ for same concept in different names.
  • Type mismatch is possible: same name, different type.
  • Enforce usage as policy.
  • Not documentation available for sharing with other teams or for your own reference.

Iteration #2: Enforcing types


This problem comes from accidentally reusing same name for different kinds of items, being "id" a paradigmatic example.
logger.info("New Market Status {} {}", kv("id", 1234), kv("newStatus", "ready"));
[...] 
logger.info("User has signed up {}", kv("id", "email@forexample.com"));

Unless forced, first occurrence of a type defines the type for that index. Therefore you will find an error as following in Logstash logs/output:

logstash_1       | [2018-11-15T22:08:29,392][WARN ][logstash.outputs.elasticsearch] 
Could not index event to Elasticsearch. {
:status=>400, 
:action=>[
  "index", {
    :_id=>nil, 
    :_index=>"vrr-leveluplogging-low-2018-11-15", 
    :_type=>"doc", 
    :_routing=>nil
  }, 
  #<LogStash::Event:0x9b41f3e>
], 
:response=>{
  "index"=>{
    "_index"=>
    "vrr-leveluplogging-low-2018-11-15", 
    "_type"=>"doc", 
    "_id"=>"hJZrGWcBSDbbRtN6HHw3", 
    "status"=>400, 
    "error"=>{
      "type"=>"illegal_argument_exception", 
      "reason"=>"mapper [id] of different type, current_type [long], merged_type [text]"
}}}}


If you check Kibana's Management -> Index Patterns -> vrr-* (in our example)


Field "id" has been defined as "number", therefore when Logstash tries to put a "string" it fails.

Once introduced the problem, let's try the solution.


import net.logstash.logback.argument.StructuredArgument;
import static net.logstash.logback.argument.StructuredArguments.kv;

public class LoggerUtils {

    public static StructuredArgument logMarketId(Long id) {
        return kv("marketId", id);
    }

    public static StructuredArgument logCustId(String id) {
        return kv("custId", id);
    }

}

We could create a helper class that centralized the responsibility of not reusing names, and name-type relationship.

It would be used like this now (old and new version):
logger.info("User has signed up {}", kv("id", "email@forexample.com"));
logger.info("User has signed up {}", logCustId("email@forexample.com"));

Yet you need to enforce creating these functions and its usage.

Cons:
  • Name or case could differ for same concept in different names
  • Type mismatch is possible, same name, different type
  • Enforce usage as policy
  • Not documentation available for sharing with other teams or for your own reference

Please notice that a field accepting a type, e.g. "id" accepting "number", also implies that it can take an array of the same type (and not only a single value); it will be handled by ElasticSearch transparently. They will be indexed as searches will return the same document for a query of either of the values in the array.


Iteration #3: Enforcing usage


How to avoid that a random developer adds their own log lines, breaking all the rules above? Good and Rogue developer below:

import net.logstash.logback.argument.StructuredArgument;
import org.slf4j.Logger;import org.slf4j.LoggerFactory; 
import static example.LoggerUtils.logCustId;
import static net.logstash.logback.argument.StructuredArguments.kv; 

[...] 

logger.info("Good developer using custom LoggerUtils {}", logCustId("email@forexample.com")); 

[...] 

logger.info("Roge developer not using custom LoggerUtils {}", kv("custId",1234L));


Fortunately for us, Checkstyle already allows to control arbitrary imports, and also allows suppresion of this rule for a given class. Let's put it together.

Checkstyle configuration forbidding usage of kv import in the project:

<module name="Checker">
    <property name="charset" value="UTF-8">

    <module name="SuppressionFilter">
        <property name="file" value="${config_loc}/suppressions.xml">
    </property></module>
    
    <module name="TreeWalker">
        <module name="IllegalImport">
            <property name="illegalClasses" value="net\.logstash\.logback\.argument\.StructuredArguments.*">
            <property name="regexp" value="true">
        </property></property></module>
    </module>
</property></module>

Making an exception with LoggerUtils class:

<suppressions>
    <suppress checks="IllegalImport" files="LoggerUtils\.java"></suppress>
</suppressions>

You could argue that there are ways to avoid this prohibition, I agree, always are.
Goal here is not to avoid by all means that a Rogue developer logged anything he liked. Goal is to avoid mistakes, and programmatically bypass this checks should really shine in a code review.

As a result of applying above configuration in our favorite build tool (Maven, Gradle, etc..) you would find a broken build (if you configure it so, and so I recommend) and an explanation as follows (Gradle output):


:compileJava
:processResources UP-TO-DATE
:classes
[ant:checkstyle] [ERROR] /home/alberto/code/leveluplogging/leveluplogging/src/main/java/example/ErrorType.java:9:1: 
Illegal import - net.logstash.logback.argument.StructuredArguments.kv. [IllegalImport]
:checkstyleMain FAILED

FAILURE: Build failed with an exception.


Cons:
  • Name or case could differ for same concept in different names.
  • Type mismatch is possible: same name, different type.
  • Enforce usage as policy.  
  • Not documentation available for sharing with other teams or for your own reference.

 

Iteration #4: Contract-first LoggerUtils code generation


A solution that kept the goodness of the three previous iterations, but focused on a "documentation first" approach (analogy of contract-first for developers) would involve, in my opinion, the following elements:

  1. A description file that explains in the closest to human language possible what are you logging that could be of any interest to anyone.
  2. A code generator application that took the description file and made some equivalent to LoggerUtils in your favorite language. 
  3. A documentation generator application that took the description file and made a full human readable documentation in your favorite markup / text format.
  4. A plugin to attack previous two steps in your build chain (Gradle plugin, Maven plugin..)
This topic will take me long enough to deserve another article. See link below "Next"
 




Next: 5 - Contract first log generator

miércoles, 30 de marzo de 2011

Other useful Maven plugins, Reporting and Site (Part III)


FindBugs Maven Plugin

FindBugs looks for bugs in Java programs. It is based on the concept of bug patterns. A bug pattern is a code idiom that is often an error. Bug patterns arise for a variety of reasons:
Difficult language features
Misunderstood API methods
Misunderstood invariants when code is modified during maintenance
Garden variety mistakes: typos, use of the wrong boolean operator

FindBugs uses static analysis to inspect Java bytecode for occurrences of bug patterns. We have found that FindBugs finds real errors in most Java software. Because its analysis is sometimes imprecise, FindBugs can report false warnings, which are warnings that do not indicate real errors. In practice, the rate of false warnings reported by FindBugs is generally less than 50%.

Usage:
[<reporting>]
<plugins>
    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>findbugs-maven-plugin</artifactId>
        <version>2.3.1</version>
        <configuration>
            <excludeFilterFile>${findBugs.excludeFilterFile}</excludeFilterFile>
        </configuration>
    </plugin>
</plugins>
[</reporting>]

Notice that you can make ignore some classes in its analysis, by putting some value on excludeFilterFile property.

Source: http://mojo.codehaus.org/findbugs-maven-plugin/index.html


Maven CheckStyle Plugin

The Checkstyle Plugin generates a report regarding the code style used by the developers. For more information about Checkstyle, see http://checkstyle.sourceforge.net/. This version of the plugin uses Checkstyle 5.0.

The plugin can be configured in the project's POM. Predefined rulesets are included with the plugin, these are: sun_checks.xml, turbine_checks.xml, avalon_checks.xml and maven_checks.xml. You can also use a custom ruleset by specifying it in the plugin configuration.

Usage:
[<reporting>]
<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-checkstyle-plugin</artifactId>
        <version>2.6</version>
        <configuration>
            <configLocation>PUT HERE YOUR CONFIGURATION</configLocation>
            <consoleOutput>true</consoleOutput>
        </configuration>

The PMD plugin allows you to automatically run the PMD code analysis tool on your project's source code and generate a site report with its results. It also supports the separate Copy/Paste Detector tool (or CPD) distributed with PMD.

The plugin accepts configuration parameters that can be used to customize the execution of the PMD tool.

Usage:
[<reporting>]
<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-pmd-plugin</artifactId>
        <version>2.5</version>
        <configuration>
            <targetJdk>${java-version}</targetJdk>
            <excludes>
                <exclude>${pmd.excludes}</exclude>
            </excludes>
        </configuration>
    </plugin>
</plugins>
[</reporting>]

Notice you can make PMD plugin to ignore some classes.


Maven Javadoc Plugin

The Javadoc Plugin uses the Javadoc tool to generate javadocs for the specified project. For more information about the standard Javadoc tool, please refer to Reference Guide.

Usage:
[<reporting>]
<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-javadoc-plugin</artifactId>
        <version>2.7</version>
    </plugin>
</plugins>
[</reporting>]

Source: http://maven.apache.org/plugins/maven-javadoc-plugin/


JMR Maven Plugin

The JXR Plugin produces a cross-reference of the project's sources. The generated reports make it easier for the user to reference or find specific lines of code. It is also handy when used with the PMD Plugin for referencing errors found in the code.

Usage:
[<reporting>]
<plugins>
    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>jxr-maven-plugin</artifactId>
        <version>2.0-beta-1</version>
    </plugin>
</plugins>
[</reporting>]


Taglist Maven Plugin


The Taglist Maven Plugin generates a report on various tags found in the code, like @todo or //TODO tags.

Usage:
[<reporting>]
<plugins>
    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>taglist-maven-plugin</artifactId>
        <version>2.4</version>
    </plugin>
</plugins>
[</reporting>]

Maven Site Plugin

All the previous plugins are meant to provide data to three possible targets. Humans, Hudson/Jenkins or Maven Site

The Site Plugin is used to generate a site for the project. The generated site also includes the project's reports that were configured in the <reporting> section of the POM.

Once you execute "mvn site", a html site is created in your target/site directory, where all or most of previous reports are presented, together with project information like developers, scm or issues.

Usage:
[<reporting>]
<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-site-plugin</artifactId>
        <version>2.0-beta-6</version>
        <configuration>
            <locales>en</locales>
            <outputEncoding>${project.reporting.outputEncoding}</outputEncoding>
        </configuration>
    </plugin>
</plugins>
[</reporting>]

martes, 11 de enero de 2011

CheckStyle configuration distribution

Content:
CheckStyle Eclipse plugin. Installation
Tunning your CheckStyle and Formatter
Every programmer working as only one
What if... I get a "Fileset from project [projectname] has no valid check configuration" Error?
CheckStyle configuration distribution

As we could see in previous posts, it is necessary to broadcast the same style for the same team, organization or project. But I only got the lower case "q" for my post due to I make you, the newbie in the company, to configure the CheckStyle XML in your IDE, for your workspace only.

Using this strategy, a 20 members team have to configure the same 20 times for every workspace, and the number of times a workspace should be changed is undetermined, but I have done it several times this month, and today is 10th of January and I did not work seriously until yesterday :S.

It no longer matter the number of times you change your workspace in your Eclipse IDE, it is simply a bad practice to charge with that duty to your team. It should be done the lesser times possible, the lesser people doing it possible, and the lesser complicated to update possible.

What I am explaining you today is the possibility of configuring CheckStyle at project scope, not IDE scope, sharing the same configuration to all your team with the same commit and, even better, referencing an external file instead a local one, making updates of style immediate for every mate without even knowing.

Erase your previous configuration:
Window Menu ->Preferences -> CheckStyle. Then select your previous home-brew configuration and Remove it.

Now configure your project:
Right click over your project, Properties -> CheckStyle -> Local Check Configurations Tab -> New.
Type: Remote Configuration
Name: Whatever, yes, there's room for creativity today.
Location: URI of the CheckStyle configuration. It would be as perfect as necessary to have the file shared in a ftp server, svn server or any other easy-access way. We settled it under svn control and access it through svn+http apache mod.
Save and close.

And voila, now all your team has to do is update the project and run CheckStyle for that project, automatically the project configuration will be token and only one person had to work for a team benefit.

This is not a perfect way of doing the distribution, but it is rather better than previous, at IDE workspace files. But this configuration seems to me to much IDE-dependant either, I am searching for a better CheckStyle configuration in the Maven descriptor file. I will tell you as soon as I really see it working.

See you.

Alberto Navarro.

viernes, 7 de enero de 2011

What if... I get a "Fileset from project [projectname] has no valid check configuration" Error?

Content:
CheckStyle Eclipse plugin. Installation
Tunning your CheckStyle and Formatter
Every programmer working as only one
What if... I get a "Fileset from project [projectname] has no valid check configuration" Error?
CheckStyle configuration distribution

One solution for the following error:

Errors occurred during the build.
Errors running builder 'Checkstyle Builder' on project [projectname].
Fileset from project [projectname] has no valid check configuration.
Fileset from project [projectname] has no valid check configuration.
Fileset from project [projectname] has no valid check configuration.
Fileset from project [projectname] has no valid check configuration.




Analysis: 

It looks like to me that you configured CheckStyle in a workspace scope (Window->Preferences->CheckStyle...). Any of your team did the same, but his/her configuration, although it is the same, he/she put a different name to the configuration.

The other person generated a checkstyle project configuration, like ignored folders, and shared it with you, through Subversion for example.

As soon as you get that configuration, Checkstyle search for a specific configuration name, your pal's one, and yours name is different. That's the error.


Solution:

Please check your .checkstyle file in the root folder of the project. Specially "fileset" node, "check-config-name" property. Its value MUST be coherent with your CheckStyle configuration name. That file must be under version control repository Subversion and is shared between developers, so it is possible that some guy imported its workspace configuration.

Example of mistaken configuration .checkstyle file:

<?xml version="1.0" encoding="UTF-8"?>
<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false">
  <fileset name="all" enabled="true" check-config-name="Sun Checks" local="false">
    <file-match-pattern match-pattern="." include-pattern="true"/>
  </fileset>
  <filter name="WriteProtectedFiles" enabled="true"/>
</fileset-config>



Coherent CheckStyle configuration at Window menu -> Preferences.


If the configuration doesn't defaults to the same name, or a project local configuration doesn't either, the error will appear. Check both IDE and project checkstyle configuration.

For avoiding the same error in the future, you can agree a name for that configuration with your team. A possible better solution is described here, and consist of configuring CheckStyle inside the project, and such information will travel with it, no more name mistaken will happen.


Did it work? Leave a comment.

See you! :)

lunes, 3 de enero de 2011

Every programmer working as only one.

Content:
CheckStyle Eclipse plugin. Installation
Tunning your CheckStyle and Formatter
Every programmer working as only one
What if... I get a "Fileset from project [projectname] has no valid check configuration" Error?
CheckStyle configuration distribution


You had paid a huge amount of money to have your house built within three months, and you got it. It has roof, kitchen and perfect thermal isolation.

You had asked for the nice brick facade in the picture but... what the f*cking hell, every damn square meter of the wall has its own colour! All right, all right,it is a house, it will keep me safe and healthy; but, for Christ's sake, there are twenty shades of "red" and it is horrible! It is a sort of Scottish skirt for a colour-blind person, weird and not exactly homogeneous.

The upset owner of this house spent all the following afternoon seeking for an answer, and he could merely complain because every labourer said more or less the same: they did their square meter as perfect as they could, but they had their own style and they will not ever work exactly as the folk to the left (and, as it is impossible, they assumed they could do whatever they liked instead), so it is pretty much the sign of the artist.


Picasso 1)
if(){
sencence;
}


picasso B)
if()
{
sencence;
}


Picasso the third)
if() sencence;


Picasso delta)
if()
    sencence;


So here you are, your house is not your home, and twenty Picassos are happily being transported to their next crime.

We have to do something...


Our imaginary brand new IT department had SpringSource, did some work with Maven, but it is high time to moderate the creativity of the guys. So review how to set up and customize CheckStyle, and let's export it to the team.

The manual way, fair enough for today, is to export both files (CheckStyle and Formatter) and send them out via mail or shared folder. My "q" is not a capital letter this evening.

Export your CheckStyle configuration:
Window menu -> preferences -> CheckStyle -> Select your configuration and click Export. Select the desired target folder and new file name.

Export your Java Formatter configuration:
Window menu -> preferences -> Java -> Code Style -> Formatter -> Select your configuration -> Edit -> Export. Select the desired target folder and new file name.


Now you have your red brick, the same red for every brick. Every artist could still put the bricks in the wrong way, but the colour of the wall would be
uniform anyway. Fire that labour if he did so as a revenge and keep working meanwhile.

Every developer in the team must now import both xml files, in the reverse most simple way.

Import your CheckStyle configuration: (Yes, I have just copy/pasted myself)
Window menu -> preferences -> CheckStyle -> type: External Configuration File, location: path+filename, name: the same name for everyone, whatever -> Ok and... Set as Default.

Import your Java Formatter configuration: (Ups, I did it again... )
Window menu -> preferences -> Java -> Code Style -> Formatter -> Import -> Select your file and it is done. Just select the new profile as the active one.


To activate CheckStyle and use Formatter, please check previous posts. Congratulations, you can truly start enjoying teamwork.

Damn artists...

pd: Thanks Javier del Palacio for your corrections. I owe you a "worker of the month". :)

martes, 28 de diciembre de 2010

Tunning your Checkstyle and Formatter

Content:
CheckStyle Eclipse plugin. Installation
Tunning your CheckStyle and Formatter
Every programmer working as only one
What if... I get a "Fileset from project [projectname] has no valid check configuration" Error?
CheckStyle configuration distribution

In the previous post, we installed Checkstyle and tested it a bit, a little proof-of-concept, useful for your little project at home, it doesn't cares anybody, and the world could survive without it perfectly.

Now focus on your company, it is unforgivable that every mate format their code as Sant Peter tells them. You implanted CheckStyle code in your I.T. dept. and it looks like better, but Sun style (default one for Formatter and CheckStyle) doesn't fit your interests.

One example. Your monitor is 1280 pixels wide, but Formatter defaults to 80 columns of text, and you find it miserable for your hardware, that supports much more, at least 120 columns.

Let's build this example, a comment of 143 columns length.



As soon as you invoke Formatter (Ctrl+Shift+F or Menu Source->Format), the result is next:


The comment line was broken at column 79, but I spent a large amount of money in a extreme-wide monitor and I find that length ridiculous. I better change this parameter.

Check your configuration in  Window menu -> Preferences -> Java -> Code Style -> Formatter. The best you can do in this point is create your own profile, based on an existent one. 

I chose New ... and type anavarro_prof, based on "Java Convention [built-in]"


Then, edit your new profile, as a sample, we will change line width...


 and comment width...



Once both parameters are changed, let's suppose your project is using the IDE default formatter, so, your formatter, that have been chosen as default one after its creation.

Return to your code, re-format it! it works! it has been formatted to 120 lines width.




Did it work? not completely... see that magnifying glass that appeared at the left side of your comment...




Line is longer than 80 characters?. What's up?
This is happening because your Formatter is not directly connected with your CheckStyle plugin, so you will have to transmit your Formatter changes into your CheckStyle configuration.


Open Window Menu -> Preferences -> CheckStyle. 

You should find the two built-in configurations, but you want to configure your own. 





So firstly select one of them, click "Copy" to create a configuration based on an already created one.



And change some parameters, as the type, make it external, change that ugly name and select a location where the new configuration will be created. I lend you an example:




Then, clicking "OK", your new configuration will be created and you can both "Set as Default" and "Configure". Yes, please, "Configure" it.


Search for "Maximum Line Length", and EDIT existent "Maximum Line Length" in the window on the right. Beware don't add an additional property already existent, because you won't get the desired goal.


Then change its maximum length doubleclicking it:




Save, Ok, Rebuild, do whatever neccesary to get your code window again, magnifying glass should dessapear after recompiling. Mine does! You have also got an external CheckStyle configurer as a xml file where you asked to. This file will be transferred to your mates in next chapter.


Quite a long article, you should have learned to customize your Formatter and make your CheckStyle configuration being Formatter-compliant. You can now impose both configurations to your entire team, in the next article, promise.


Have a happy New Year's Eve!!!