io.djigger.collector.accessors.InstrumentationEventAccessor.java Source code

Java tutorial

Introduction

Here is the source code for io.djigger.collector.accessors.InstrumentationEventAccessor.java

Source

/*******************************************************************************
 * (C) Copyright 2016 Jrme Comte and Dorian Cransac
 *  
 *  This file is part of djigger
 *  
 *  djigger is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  
 *  djigger is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *  
 *  You should have received a copy of the GNU Affero General Public License
 *  along with djigger.  If not, see <http://www.gnu.org/licenses/>.
 *
 *******************************************************************************/
package io.djigger.collector.accessors;

import static com.mongodb.client.model.Filters.and;
import static com.mongodb.client.model.Filters.gt;
import static com.mongodb.client.model.Filters.lt;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;

import org.bson.BsonArray;
import org.bson.BsonString;
import org.bson.BsonValue;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;

import io.djigger.collector.accessors.stackref.AbstractAccessor;
import io.djigger.model.TaggedInstrumentationEvent;
import io.djigger.monitoring.java.instrumentation.InstrumentationEvent;
import io.djigger.monitoring.java.instrumentation.InstrumentationEventData;
import io.djigger.monitoring.java.instrumentation.InstrumentationEventWithThreadInfo;
import io.djigger.monitoring.java.instrumentation.StringInstrumentationEventData;
import io.djigger.monitoring.java.model.StackTraceElement;
import io.djigger.monitoring.java.model.ThreadInfo;

public class InstrumentationEventAccessor extends AbstractAccessor {

    private static final Logger logger = LoggerFactory.getLogger(InstrumentationEventAccessor.class);

    private static final Logger eventWriter = LoggerFactory.getLogger("InstrumentationEventWriter");

    MongoDatabase db;

    MongoCollection<Document> instrumentationEventsCollection;

    public InstrumentationEventAccessor(MongoDatabase db) {
        super();

        this.db = db;
        instrumentationEventsCollection = db.getCollection("instrumentation");
    }

    public void createIndexesIfNeeded(Long ttl) {
        createOrUpdateTTLIndex(instrumentationEventsCollection, "start", ttl);
        createOrUpdateIndex(instrumentationEventsCollection, "tagged");
    }

    public void save(TaggedInstrumentationEvent event) {
        Document doc = toDocument(event);

        log(doc);

        instrumentationEventsCollection.insertOne(doc);
    }

    public Iterator<InstrumentationEvent> getByParentId(ObjectId parentId) {
        Bson filter = new Document("parentid", parentId);
        return query(filter);
    }

    public Iterator<InstrumentationEvent> getByTransactionId(UUID transactionIDd) {
        Bson filter = new Document("trid", transactionIDd.toString());
        return query(filter);
    }

    public Iterator<InstrumentationEvent> get(Bson filter, Date from, Date to) {
        Bson query = buildQuery(filter, from, to);

        return query(query);
    }

    public Iterator<InstrumentationEvent> getTaggedEvents(Bson filter, Date from, Date to) {
        Bson query = buildQuery(filter, from, to);
        //query = and(query,new Document("tagged", true));
        return query(query);
    }

    private Iterator<InstrumentationEvent> query(Bson query) {
        final MongoCursor<Document> documents = instrumentationEventsCollection.find(query).iterator();
        return new Iterator<InstrumentationEvent>() {

            @Override
            public boolean hasNext() {
                return documents.hasNext();
            }

            @Override
            public InstrumentationEvent next() {
                Document doc = documents.next();
                InstrumentationEvent event = fromDocument(doc);
                return event;
            }

            private InstrumentationEvent fromDocument(Document doc) {

                InstrumentationEvent event;
                if (doc.containsKey("stacktrace")) {
                    event = new InstrumentationEventWithThreadInfo(doc.getString("class"), doc.getString("method"));

                    StackTraceElement[] stacktrace = fromDBObject(doc.get("stacktrace"));
                    ThreadInfo info = new ThreadInfo(stacktrace);
                    ((InstrumentationEventWithThreadInfo) event).setThreadInfo(info);
                } else {
                    event = new InstrumentationEvent(doc.getString("class"), doc.getString("method"));
                }

                event.setStart(doc.getDate("start").getTime());
                event.setDuration(doc.getLong("duration"));
                event.setId(doc.getObjectId("_id"));
                event.setThreadID(doc.getLong("threadid"));
                event.setParentID(doc.getObjectId("parentid"));
                //            event.setTransactionID((UUID) doc.get("trid"));
                event.setTransactionID(UUID.fromString(doc.getString("trid")));

                if (doc.containsKey("data")) {
                    List<?> array = (List<?>) doc.get("data");
                    List<InstrumentationEventData> list = new LinkedList<InstrumentationEventData>();
                    for (Object value : array) {
                        list.add(new StringInstrumentationEventData((String) value));
                    }
                    event.setData(list);
                }

                return event;
            }

            private StackTraceElement[] fromDBObject(Object o) {
                @SuppressWarnings("unchecked")
                List<List<Object>> l = (List<List<Object>>) o;
                StackTraceElement[] s = new StackTraceElement[l.size()];
                for (int i = 0; i < l.size(); i++) {
                    List<Object> e = (List<Object>) l.get(i);
                    s[i] = new StackTraceElement((String) e.get(0), (String) e.get(1), (String) e.get(2),
                            (int) e.get(3));
                }
                return s;
            }

            @Override
            public void remove() {
                throw new RuntimeException("Not implemented");
            }
        };
    }

    private Bson buildQuery(Bson mongoQuery, Date from, Date to) {
        Bson result = and(gt("start", from), lt("start", to));
        if (mongoQuery != null) {
            result = and(mongoQuery, result);
        }
        return result;
    }

    public void save(List<TaggedInstrumentationEvent> events) {
        List<Document> documents = new ArrayList<>();
        for (TaggedInstrumentationEvent instrumentationEvent : events) {
            Document document = toDocument(instrumentationEvent);

            documents.add(document);

            log(document);
        }
        instrumentationEventsCollection.insertMany(documents);
    }

    private void log(Document document) {
        if (eventWriter.isTraceEnabled()) {
            eventWriter.trace(document.toJson());
        }
    }

    private Document toDocument(TaggedInstrumentationEvent taggedEvent) {
        Document doc = new Document();
        InstrumentationEvent event = taggedEvent.getEvent();
        doc.append("class", event.getClassname());
        doc.append("method", event.getMethodname());
        doc.append("start", new Date(event.getStart()));
        doc.append("duration", event.getDuration());
        doc.append("threadid", event.getThreadID());
        doc.append("trid", event.getTransactionID().toString());
        doc.append("_id", event.getId());
        doc.append("parentid", event.getParentID());
        if (taggedEvent.getTags() != null) {
            doc.append("tagged", true);
            doc.putAll(taggedEvent.getTags());
        }
        if (event instanceof InstrumentationEventWithThreadInfo) {
            List<Object> stacktrace = stackTraceAsTable(
                    ((InstrumentationEventWithThreadInfo) event).getThreadInfo());
            doc.append("stacktrace", stacktrace);
        }
        List<InstrumentationEventData> data = event.getData();
        if (data != null) {
            BsonArray array = new BsonArray();
            for (InstrumentationEventData eventData : data) {
                if (eventData instanceof StringInstrumentationEventData) {
                    array.add(new BsonString(((StringInstrumentationEventData) eventData).getPayload()));
                }
            }
            doc.append("data", array);
        }

        return doc;
    }

    private static List<Object> stackTraceAsTable(ThreadInfo info) {
        StackTraceElement[] stacktrace = info.getStackTrace();
        ArrayList<Object> table = new ArrayList<>(stacktrace.length);

        for (int i = 0; i < stacktrace.length; i++) {
            StackTraceElement e = stacktrace[i];
            ArrayList<Object> node = new ArrayList<Object>();
            node.add(e.getClassName());
            node.add(e.getMethodName());
            node.add(e.getFileName());
            node.add(e.getLineNumber());
            table.add(node);
        }
        return table;
    }
}