Skip to main content
Skip table of contents

How can I log the number of documents / bytes I've processed?

I want to log the number of documents I've processed using iText, as well as the number of bytes I've read or produced.
Is there a logging mechanism that allows me to do this?

Question asked at an internal meeting at iText Group NV.

Please note that the following method is deprecated as of iText 7.1.4. For an updated example, see "How can I count the number of PDF reads and writes in iText 7?" in the Volume Counter FAQs.

Please take a look at the CounterDemoStandardOut example. In this example, we get an instance of the CounterFactory. Simultaneously, we create a new SystemOutCounter object, which is an implementation of the Counter interface that writes information to the console (System.out):

JAVA
CounterFactory.getInstance().setCounter(new SystemOutCounter());

We can now use ordinary iText code without having to worry about counting bytes or documents; that single line activated the counting mechanism.

For instance, we can create a PDF:

JAVA
private void createPdf(String src) throws FileNotFoundException {
    Document document = new Document(new PdfDocument(new PdfWriter(src)));
    document.add(new Paragraph("Hello World!"));
    document.close();
}

Or we can manipulate a PDF:

JAVA
public void manipulatePdf(String src, String dest) throws IOException {
    CounterFactory.getInstance().setCounter(new SystemOutCounter());

    createPdf(src);
    PdfReader reader = new PdfReader(src);
    PdfDocument pdfDocument = new PdfDocument(reader, new PdfWriter(dest));
    Document document = new Document(pdfDocument).showTextAligned(new Paragraph("Stamped text"), 559, 806, TextAlignment.RIGHT);
    document.close();

    CounterFactory.getInstance().setCounter(new DefaultCounter());
}

If we execute createPdf() and manipulatePdf(), the SystemOutCounter will automatically write the following information to the System.out:

XML
[com.itextpdf.kernel.pdf.PdfDocument] 929 bytes written
[com.itextpdf.kernel.pdf.PdfDocument] 929 bytes read
[com.itextpdf.kernel.pdf.PdfDocument] 1 389 bytes written

In the first line, we see that PdfDocument wrote 929 bytes (this happened in the createPdf() method). In the second and third line, we see what happened in the manipulatePdf() method: PdfDocument has read 929 bytes and we added the text "Stamped text" resulting in 1389 bytes.

This is only a simple example that writes to the System.out. It's not difficult to write some code that stores this information (and more) in another place. Let's take a look at the CounterDemo example. In this example, we write our own implementation of the Counter interface so that information about the processed documents is written to a file.

We need to implement three methods:

  • getCounter(): this method will return an instance of your counter,

  • onDocumentRead(long size): this method will be triggered when a file is read,

  • onDocumentWritten(long size): this method will be triggered when a file is written.

We implemented these methods as follows:

JAVA
public class MyCounter implements Counter {

    protected FileWriter writer;
    protected String yourClass;
    protected String iTextClass;

    public MyCounter(Class> klass) throws IOException {
        this.yourClass = klass.getName();
        writer = new FileWriter(LOG_RESULT, false);
    }

    private MyCounter(Class> klass, String yourClass, FileWriter writer)
            throws IOException {
        this.yourClass = yourClass;
        this.iTextClass = klass.getName();
        this.writer = writer;
    }

    @Override
    public Counter getCounter(Class> klass) {
        try {
            return new MyCounter(klass, yourClass, writer);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void onDocumentRead(long size) {
        if (writer == null)
            throw new RuntimeException("No writer defined!");
        try {
            writer.write(String.format(
                    "[%s:%s] %s: %s read\n", yourClass, iTextClass, new Date().toString(), size));
            writer.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void onDocumentWritten(long size) {
        if (writer == null)
            throw new RuntimeException("No writer defined!");
        try {
            writer.write(String.format(
                    "[%s:%s] %s: %s written\n", yourClass, iTextClass, new Date().toString(), size));
            writer.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void close() throws IOException {
        writer.close();
    }
}

As you see, instead of writing to the System.out, we will write to that file using the writer object. The yourClass object will store the class name of your application that uses the Counter; the iTextClass object will store the iText class that reads, writes or manipulates the PDF document.

The private constructor will be called by iText internally through the getCounter() method. It initializes the iTextClass variable and passes the yourClass and writer variables as parameters.

When bytes are read, we will write information to the log file that looks like this:

XML
String.format("[%s:%s] %s: %s read\n", yourClass, iTextClass, new Date().toString(), size)

When bytes are written, we will write information to the log file that looks like:

XML
String.format("[%s:%s] %s: %s written\n", yourClass, iTextClass, new Date().toString(), size)

If we execute the same createPdf() and manipulatePdf() methods as before, we get the following result:

XML
[qa.general_questions.how_can_i_log_the_number_of_documents.CounterDemo:com.itextpdf.kernel.pdf.PdfDocument] Thu Jul 21 15:09:47 MSK 2016: 929 written
[qa.general_questions.how_can_i_log_the_number_of_documents.CounterDemo:com.itextpdf.kernel.pdf.PdfDocument] Thu Jul 21 15:09:47 MSK 2016: 929 read
[qa.general_questions.how_can_i_log_the_number_of_documents.CounterDemo:com.itextpdf.kernel.pdf.PdfDocument] Thu Jul 21 15:09:47 MSK 2016: 1389 written

As we are writing to a file, we mustn't forget to close the FileWriter once we've finished reading and writing documents:

JAVA
public void close() throws IOException {
        writer.close();
    }

This example is provided FYI. Feel free to change the behavior of the FileWriter.

Caveat: The CounterFactory is currently implemented as a singleton that stores a single Counter instance. This means that you can only store a single Counter at a time for each JVM.

Click How can I log the number of documents / bytes I've processed? if you want to see how to answer this question in iText 5.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.