1

In our back-end systems, there are many situations to update object, e.g. update goods, update goods prices, update user, update status, update order(cancel, update price) and so on. Now some object we have a specially log table, e.g. order_update_log , to logger update operations. Some only logger to file, e.g.

logger.info("goods update: before: {}, after: {}", oldGoods, newGoods)

Feel process these trivial things very annoying, does exist some better manner/tools to process logger like this?

antonu17
  • 523
  • 4
  • 15
zhuguowei
  • 8,401
  • 16
  • 70
  • 106
  • I understand you want to log something, but what do you want to achieve exactly? Which kind of information do you need to log? – Matt Nov 19 '15 at 12:01
  • If I understood correctly, these update-logs annoy you when they are in the common application logs. You can configure a special Logger for them. In code you have to reference that (additional) Logger like `Logger updLog = LogManager.getLogger("UPDATELOG");`. Then use that logger instance for the updates. In the Config, you can then add appenders to that logger, etc. – Fildor Nov 19 '15 at 12:22
  • Thanks! Say simply that is I want to record object update track, e.g who did what at some time, meantime developer could get rid of this work, like spring help develop to process transaction and dependency injection. – zhuguowei Nov 19 '15 at 12:26

2 Answers2

1

If you are using an ORM to persist your data you can use something like Hibernate's Listners/events to respond to data updates (and log them to the DB, or to an audit-log etc.) For hibernate the information is detailed here: https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/events.html but obviously you would need to investigate what if anything your persistence tools provided to you.

Goibniu
  • 2,212
  • 3
  • 34
  • 38
1

There is very nice thing called Aspects. You can write aspect for you project that is only aware of tracking changes of goods objects. Supposing you have Goods class:

public class Goods {
    private Integer id;
    private String name;
    private BigDecimal cost;

    // Getters, Setters
    ...
}

which mapped to database table goods with corresponding fields:

CREATE TABLE `goods` (
    `id` INT NOT NULL AUTO_INCREMENT,
    `name` varchar NOT NULL,
    `cost` DECIMAL NOT NULL,
    PRIMARY KEY (`id`)
);

Supposing you have GoodsService:

public class GoodsService {

    public Goods read(Integer id) {
        Goods goods = /* Read goods from database */
        return goods;
    }

    public void write(Goods goods) {
        /* Write goods to database */
    }
}

and GoodsController that using GoodsService:

public class GoodsController {

    private GoodsService goodsService;

    public void updateGoods(Integer id, String name, BigDecimal cost) {
        Goods goods = goodsService.read(id);
        goods.setName(name);
        goods.setCost(cost);
        goodsService.write(goods);
    }

}

So lets add some aspects magic to your project for tracking changes of goods. Now create another table with additional fields for storing user and datetime of updating goods object:

CREATE TABLE `goods_log` (
    `revision` INT NOT NULL AUTO_INCREMENT,
    `id` INT NOT NULL,
    `name` varchar NOT NULL,
    `cost` DECIMAL NOT NULL,
    `user` varchar NOT NULL,
    `timestamp` DATETIME NOT NULL,
    PRIMARY KEY (`revision`,`id`)
);

Write aspect class:

@Aspect
public class GoodsLogger {
    @Before(value = "execution(* org.antonu.service.GoodsService.write(..)) && args(goods)")
    public void logWrite(Goods goods) {
        // Get current user and timestamp,
        // Write it to goods_log table, as well as goods data
    }
}

That's it! Your business logic code didn't change, it's clear to read. But every time GoodsService's write method invoked you will get record in goods_log with new state of goods.

To make this code working it should be compiled with AJC compiler, also aspectjrt library should be included. It can be easily done via maven:

<properties>
    <aspectj.version>1.8.7</aspectj.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.4</version>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjrt</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjtools</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

Modern IDE Intellij Idea should automatically use AJC compiler with maven config above. If not, you must configure compiler via File - Settings - 'Build, Execution, Deployment' - Compiler - Java Compiler - Use compiler: Ajc. Path to AJC compiler: <path_to>/aspectjtools-1.8.7.jar

antonu17
  • 523
  • 4
  • 15