Created
July 21, 2015 13:07
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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