Skip to content

Instantly share code, notes, and snippets.

@newyankeecodeshop
Created July 21, 2015 13:07
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save newyankeecodeshop/a1226709f36ec59e2269 to your computer and use it in GitHub Desktop.
Liquibase change listener that generates a JSON file based on the change sets executed. It uses Jackson for JSON generation.
import java.io.File
import java.sql.Timestamp
import java.util.concurrent.ConcurrentHashMap
import com.fasterxml.jackson.core.{JsonEncoding, JsonFactory}
import liquibase.change.Change
import liquibase.changelog.ChangeSet.{ExecType, RunStatus}
import liquibase.changelog.visitor.ChangeExecListener
import liquibase.changelog.{ChangeSet, DatabaseChangeLog}
import liquibase.database.Database
import liquibase.exception.{PreconditionErrorException, PreconditionFailedException}
import liquibase.precondition.core.PreconditionContainer.{ErrorOption, FailOption}
import liquibase.sqlgenerator.SqlGeneratorFactory
import liquibase.statement.core.SetColumnRemarksStatement
import liquibase.util.ISODateFormat
/**
* A change listener that records timing and information about a run in a JSON file.
*/
class JsonChangeExecListener(jsonFile: File) extends ChangeExecListener {
val timings = new ConcurrentHashMap[String, Long]()
val timeFormat = new ISODateFormat
val jsonFactory = new JsonFactory
val jsonWriter = jsonFactory.createGenerator(jsonFile, JsonEncoding.UTF8)
jsonWriter.useDefaultPrettyPrinter()
jsonWriter.writeStartObject()
jsonWriter.writeStringField("time", timeFormat.format(new Timestamp(System.currentTimeMillis())))
jsonWriter.writeArrayFieldStart("events")
def close(): Unit = {
jsonWriter.writeEndArray()
jsonWriter.writeEndObject()
jsonWriter.close()
}
override def willRun(changeSet: ChangeSet, databaseChangeLog: DatabaseChangeLog,
database: Database, runStatus: RunStatus): Unit = {
timings.put(changeSet.getId, System.currentTimeMillis())
}
override def ran(changeSet: ChangeSet, databaseChangeLog: DatabaseChangeLog,
database: Database, execType: ExecType): Unit = {
val time = System.currentTimeMillis() - timings.get(changeSet.getId)
val statements = changeSet.getChanges.get(0)
.generateStatements(database)
.filterNot(_.isInstanceOf[SetColumnRemarksStatement])
jsonWriter.writeStartObject()
jsonWriter.writeStringField("id", changeSet.getId)
jsonWriter.writeStringField("file", changeSet.getFilePath)
jsonWriter.writeStringField("status", execType.value)
jsonWriter.writeStringField("timing", time + "ms")
jsonWriter.writeArrayFieldStart("sql")
for (statement <- statements) {
for (sql <- SqlGeneratorFactory.getInstance.generateSql(statement, database)) {
jsonWriter.writeString(sql.toSql)
}
}
jsonWriter.writeEndArray()
jsonWriter.writeEndObject()
}
override def runFailed(changeSet: ChangeSet, databaseChangeLog: DatabaseChangeLog,
database: Database, exception: Exception): Unit = {
jsonWriter.writeStartObject()
jsonWriter.writeStringField("id", changeSet.getId)
jsonWriter.writeStringField("file", changeSet.getFilePath)
jsonWriter.writeStringField("status", ExecType.FAILED.value)
jsonWriter.writeStringField("error", exception.getMessage)
jsonWriter.writeEndObject()
}
override def willRun(change: Change, changeSet: ChangeSet, changeLog: DatabaseChangeLog,
database: Database): Unit = {
}
override def ran(change: Change, changeSet: ChangeSet, changeLog: DatabaseChangeLog,
database: Database): Unit = {
// This method is called inside ChangeSet.java before the transaction is committed.
// The version above is more useful
}
override def rolledBack(changeSet: ChangeSet, databaseChangeLog: DatabaseChangeLog,
database: Database): Unit = {
}
override def preconditionErrored(error: PreconditionErrorException, onError: ErrorOption): Unit = {
}
override def preconditionFailed(error: PreconditionFailedException, onFail: FailOption): Unit = {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment