Show Navigation

JavaMelody monitoring with Grails 3

Learn how to setup and monitor your application using JavaMelody

Authors: Ben Rhine

Grails Version: 3.3.2

1 Training

Grails Training - Developed and delivered by the folks who created and actively maintain the Grails framework!.

2 Getting Started

In this guide we will show you how to setup and use JavaMelody with a Grails 3 application. We will be using the grails-melody-plugin

2.1 What you will need

To complete this guide, you will need the following:

  • Some time on your hands

  • A decent text editor or IDE

  • JDK 1.7 or greater installed with JAVA_HOME configured appropriately

2.2 How to complete the guide

To get started do the following:

or

The Grails guides repositories contain two folders:

  • initial Often a simple Grails app with some additional code to give you a head-start.

  • complete

In this guide you are going to create a Grails Application. The complete app is a completed example. It is the result of working through the steps presented by the guide and applying those changes to the initial folder.

To complete the guide, go to the initial folder

  • cd into grails-guides/grails-javamelody/initial

and follow the instructions in the next sections.

You can go right to the completed example if you cd into grails-guides/grails-javamelody/complete.

3 Application Overview

In this guide we will add monitoring to our application so we can collect statistics about how our app is performing. First we will build an app which lists books and the book’s details, after which we will add the monitoring and discuss what we can do with it.

3.1 Books Application

We have already placed the base app in the initial folder for you.

To quickly cover how to create the app, we first need to add a Book domain.

grails-app/domain/demo/Book.groovy
package demo

import grails.compiler.GrailsCompileStatic

@GrailsCompileStatic
class Book {
    String image
    String title
    String author
    String about
    String href
    static mapping = {
        about type: 'text'
    }
}

The home page displays a list of books. We only need a subset of data from each book. Namely, the unique identifier and the book cover image. Create a Groovy POGO to encapsulate that information in the src/main/groovy directory

src/main/groovy/demo/BookImage.groovy
package demo

import groovy.transform.CompileStatic

@CompileStatic
class BookImage {
    Long id
    String image
}

Create default CRUD actions for Book leveraging GORM data services.

grails-app/services/demo/BookDataService.groovy
package demo

import grails.gorm.services.Service
import grails.gorm.transactions.ReadOnly
import groovy.transform.CompileDynamic
import groovy.transform.CompileStatic
import org.grails.datastore.mapping.query.api.BuildableCriteria
import org.hibernate.transform.Transformers

interface IBookDataService {
    Book save(String title, String author, String about, String href, String image)
    Number count()
    Book findById(Long id)
}

@Service(Book)
abstract class BookDataService implements IBookDataService {

    @CompileDynamic
    @ReadOnly
    List<BookImage> findAll() {
        BuildableCriteria c = Book.createCriteria()
        c.list {
            resultTransformer(Transformers.aliasToBean(BookImage))
            projections {
                property('id', 'id')
                property('image', 'image')
            }
        }
    }
}

Next, create a controller which consumes the service that we just created. Our index will leverage our custom findAll to return a complete list of books while our show will make use of the data services findById.

grails-app/controllers/demo/BookController.groovy
package demo

import groovy.transform.CompileStatic

@CompileStatic
class BookController {

    static allowedMethods = [index: 'GET', show: 'GET']

    BookDataService bookDataService

    def index() {
        [bookList: bookDataService.findAll()]
    }

    def show(Long id) {
        [bookInstance: bookDataService.findById(id)]
    }

}

Then we need to actually create the book data with our Bootstrap.groovy

grails-app/init/demo/Bootstrap.groovy
package demo

import groovy.transform.CompileStatic

@CompileStatic
class BootStrap {

    public final static List< Map<String, String> > GRAILS_BOOKS = [
            [
                    title : 'Grails 3 - Step by Step',
                    author: 'Cristian Olaru',
                    href: 'https://grailsthreebook.com/',
                    about : 'Learn how a complete greenfield application can be implemented quickly and efficiently with Grails 3 using profiles and plugins. Use the sample application that accompanies the book as an example.',
                    image: 'grails_3_step_by_step.png',
            ],
            [
                    title : 'Practical Grails 3',
                    author: ' Eric Helgeson',
                    href  : 'https://www.grails3book.com/',
                    about : 'Learn the fundamental concepts behind building Grails applications with the first book dedicated to Grails 3. Real, up-to-date code examples are provided, so you can easily follow along.',
                    image: 'pratical-grails-3-book-cover.png',
            ],
            [
                    title : 'Falando de Grails',
                    author: 'Henrique Lobo Weissmann',
                    href  : 'http://www.casadocodigo.com.br/products/livro-grails',
                    about : 'This is the best reference on Grails 2.5 and 3.0 written in Portuguese. It&#39;s a great guide to the framework, dealing with details that many users tend to ignore.',
                    image: 'grails_weissmann.png',
            ],
            [
                    title : 'Grails Goodness Notebook',
                    author: 'Hubert A. Klein Ikkink',
                    href  : 'https://leanpub.com/grails-goodness-notebook',
                    about : 'Experience the Grails framework through code snippets. Discover (hidden) Grails features through code examples and short articles. The articles and code will get you started quickly and provide deeper insight into Grails.',
                    image: 'grailsgood.png',
            ],
            [
                    title : 'The Definitive Guide to Grails 2',
                    author: 'Jeff Scott Brown and Graeme Rocher',
                    href  : 'http://www.apress.com/9781430243779',
                    about : 'As the title states, this is the definitive reference on the Grails framework, authored by core members of the development team.',
                    image: 'grocher_jbrown_cover.jpg',
            ],
            [
                    title : 'Grails in Action',
                    author: 'Glen Smith and Peter Ledbrook',
                    href  : 'http://www.manning.com/gsmith2/',
                    about : 'The second edition of Grails in Action is a comprehensive introduction to Grails 2 focused on helping you become super-productive fast.',
                    image: 'gsmith2_cover150.jpg',
            ],
            [
                    title : 'Grails 2: A Quick-Start Guide',
                    author: 'Dave Klein and Ben Klein',
                    href  : 'http://www.amazon.com/gp/product/1937785777?tag=misa09-20',
                    about : 'This revised and updated edition shows you how to use Grails by iteratively building a unique, working application.',
                    image : 'bklein_cover.jpg',
            ],
            [
                    title : 'Programming Grails',
                    author: 'Burt Beckwith',
                    href  : 'http://shop.oreilly.com/product/0636920024750.do',
                    about : 'Dig deeper into Grails architecture and discover how this application framework works its magic.',
                    image: 'bbeckwith_cover.gif'
            ]
    ] as List< Map<String, String> >

    public final static List< Map<String, String> > GROOVY_BOOKS = [
            [
                    title: 'Making Java Groovy',
                    author: 'Ken Kousen',
                    href: 'http://www.manning.com/kousen/',
                    about: 'Make Java development easier by adding Groovy. Each chapter focuses on a task Java developers do, like building, testing, or working with databases or restful web services, and shows ways Groovy can make those tasks easier.',
                    image: 'Kousen-MJG.png',
            ],
            [
                    title: 'Groovy in Action, 2nd Edition',
                    author: 'Dierk König, Guillaume Laforge, Paul King, Cédric Champeau, Hamlet D\'Arcy, Erik Pragt, and Jon Skeet',
                    href: 'http://www.manning.com/koenig2/',
                    about: 'This is the undisputed, definitive reference on the Groovy language, authored by core members of the development team.',
                    image: 'regina.png',
            ],
            [
                    title: 'Groovy for Domain-Specific Languages',
                    author: 'Fergal Dearle',
                    href: 'http://www.packtpub.com/groovy-for-domain-specific-languages-dsl/book',
                    about: 'Learn how Groovy can help Java developers easily build domain-specific languages into their applications.',
                    image: 'gdsl.jpg',
            ],
            [
                    title: 'Groovy 2 Cookbook',
                    author: 'Andrey Adamovitch, Luciano Fiandeso',
                    href: 'http://www.packtpub.com/groovy-2-cookbook/book',
                    about: 'This book contains more than 90 recipes that use the powerful features of Groovy 2 to develop solutions to everyday programming challenges.',
                    image: 'g2cook.jpg',
            ],
            [
                    title: 'Programming Groovy 2',
                    author: 'Venkat Subramaniam',
                    href: 'http://pragprog.com/book/vslg2/programming-groovy-2',
                    about: 'This book helps experienced Java developers learn to use Groovy 2, from the basics of the language to its latest advances.',
                    image: 'vslg2.jpg'
            ],
    ] as List< Map<String, String> >

    BookDataService bookDataService

    def init = { servletContext ->
        for (Map<String, String> bookInfo : (GRAILS_BOOKS + GROOVY_BOOKS)) {
            bookDataService.save(bookInfo.title, bookInfo.author, bookInfo.about, bookInfo.href, bookInfo.image)
        }
    }

    def destroy = {
    }
}

Lastly, we update our URL mapping so that the default endpoint / displays a list of books.

grails-app/controllers/demo/UrlMappings.groovy
package demo

class UrlMappings {

    static mappings = {
        "/$controller/$action?/$id?(.$format)?"{
            constraints {
                // apply constraints here
            }
        }

        "/"(controller: "book") (1)
        "500"(view:'/error')
        "404"(view:'/notFound')
    }
}
1 Updated default URL

Run the app

$ ./gradlew bootRun
booksHome

4 Adding Melody

Add monitoring to the app with JavaMelody. First, add the required dependency.

build.gradle
compile 'org.grails.plugins:grails-melody-plugin:1.70.0'

Sometimes, when using a Grails plugin you want to upgrade a transitive dependency which the plugin author has not yet upgraded. If you run the gradle task dependencies, you will see the next dependency graph.

\--- org.grails.plugins:grails-melody-plugin:1.70.0
     +--- net.bull.javamelody:javamelody-core:1.70.0
     |    \--- org.jrobin:jrobin:1.5.9
     +--- com.lowagie:itext:2.1.7
     \--- org.jrobin:jrobin:1.5.9

You can upgrade to the latest version of Java Melody 1.71.0 easily:

build.gradle
compile('org.grails.plugins:grails-melody-plugin:1.70.0') {
    exclude group: 'net.bull.javamelody', module: 'javamelody-core'
}
compile 'net.bull.javamelody:javamelody-core:1.71.0'

And …​ that’s it, with JavaMelody now added to our application, restart the app and then navigate to http://localhost:8080/monitoring and you should see the following.

melodyHome

At this point go click around the app and then return to the JavaMelody home page and expand details to see that it has caught your activity in the app. By default JavaMelody looks at your URIs to resolve HTTP Requests. This means that /book/1 and /book/6 will be listed separately.

melodyIndependentMonitoring

If you do not want to get separate statistics per book, but an aggregate of the book detail endpoint, you can tell JavaMelody to report on requests in aggregate. In our application.yml. add the following:

grails-app/conf/application.yml
javamelody:
    # filter out numbers from URI
    http-transform-pattern: \d+

Now once you have restarted the app so it picks up our config changes, do the same as last time, navigate to a few different books then return to http://localhost:8080/monitoring and expand the details to see the aggregate data across multiple requests.

melodyCombinedMonitoring

From the home screen you can easily filter your application statistics over different periods of time by selecting Day, Week, Month, Year, All, or define a Customized range in which to view stats. Additionally if you want to get a copy of all JavaMelody metrics for offline viewing click the PDF button to download a copy.

If you want the ability to enable and disable JavaMelody easily just add the following to your application.yml to be able to easily toggle monitoring on and off.

grails-app/conf/application.yml
javamelody:
    disabled: true

Similarly to HTTP request, you can aggregate stats for SQL monitoring. Add the following to your application.yml.

grails-app/conf/application.yml
javamelody:
    sql-transform-pattern: \d+

If you are using Spring Security Core and Java Melody plugins in the same app, you will need to configure the security access to the /monitoring endpoint.

grails-app/conf/application.yml
grails:
  plugin:
    springsecurity:
      controllerAnnotations:
        staticRules:
          -
            pattern: /monitoring
            access:
              - ROLE_ADMIN

Adding the previous configuration to application.yml means you will need to be authenticated with a user who has ROLE_ADMIN access to access the /monitoring.

5 Next Steps

To further your understanding, read through the Java Melody’s project documentation, Additionally feel free browse the wiki. If you have more advanced needs look Java Melody User Advanced Guide.

6 Do you need help with Grails?

OCI sponsored the creation of this Guide. OCI offers several Grails services:

Free consultation

The OCI Grails Team includes Grails co-founders, Jeff Scott Brown and Graeme Rocher. Check our Grails courses and learn from the engineers who developed, matured and maintain Grails.

Grails OCI Team