All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.eg.agent.android.harvest.Harvester Maven / Gradle / Ivy

There is a newer version: 2.1.3
Show newest version
package com.eg.agent.android.harvest;

/*import com.newrelic.agent.android.Agent;
import com.newrelic.agent.android.AgentConfiguration;
import com.newrelic.agent.android.FeatureFlag;
import com.newrelic.agent.android.TaskQueue;
import com.newrelic.agent.android.activity.config.ActivityTraceConfiguration;
import com.newrelic.agent.android.activity.config.ActivityTraceConfigurationDeserializer;
import com.newrelic.agent.android.analytics.AnalyticAttribute;
import com.newrelic.agent.android.analytics.AnalyticsControllerImpl;
import com.newrelic.agent.android.analytics.EventManager;
import com.newrelic.agent.android.logging.AgentLog;
import com.newrelic.agent.android.logging.AgentLogManager;
import com.newrelic.agent.android.stats.StatsEngine;
import com.newrelic.agent.android.tracing.ActivityTrace;
import com.newrelic.com.google.gson.GsonBuilder;*/

import com.eg.agent.android.Agent;
import com.eg.agent.android.AgentConfiguration;
import com.eg.agent.android.FeatureFlag;
import com.eg.agent.android.activity.config.ActivityTraceConfiguration;
import com.eg.agent.android.activity.config.ActivityTraceConfigurationDeserializer;
import com.eg.agent.android.analytics.AnalyticAttribute;
import com.eg.agent.android.analytics.AnalyticsControllerImpl;
import com.eg.agent.android.analytics.EventManager;
import com.eg.agent.android.TaskQueue;
import com.eg.agent.android.logging.AgentLog;
import com.eg.agent.android.logging.AgentLogManager;
import com.eg.agent.android.stats.StatsEngine;
import com.eg.agent.android.trace.ActivityTrace;
import com.eg.google.gson.GsonBuilder;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class Harvester {
    private AgentConfiguration agentConfiguration;
    private HarvestConfiguration configuration = HarvestConfiguration.getDefaultHarvestConfiguration();
    private HarvestConnection harvestConnection;
    private HarvestData harvestData;
    private final Collection harvestListeners = new ArrayList();
    private final AgentLog log = AgentLogManager.getAgentLog();
    private State state = State.UNINITIALIZED;
    protected boolean stateChanged;

    protected enum State {
        UNINITIALIZED,
        DISCONNECTED,
        CONNECTED,
        DISABLED
    }

    public void start() {
        fireOnHarvestStart();
    }

    public void stop() {
        fireOnHarvestStop();
    }

    protected void uninitialized() {
        if (this.agentConfiguration == null) {
            this.log.error("Agent configuration unavailable.");
            return;
        }
        if (Agent.getImpl().updateSavedConnectInformation()) {
            configureHarvester(HarvestConfiguration.getDefaultHarvestConfiguration());
            this.harvestData.getDataToken().clear();
        }
        Harvest.setHarvestConnectInformation(new ConnectInformation(Agent.getApplicationInformation(), Agent.getDeviceInformation()));
        this.harvestConnection.setApplicationToken(this.agentConfiguration.getApplicationToken());
        this.harvestConnection.setCollectorHost(this.agentConfiguration.getCollectorHost());
        this.harvestConnection.useSsl(this.agentConfiguration.useSsl());
        transition(State.DISCONNECTED);
        execute();
    }

    protected void disconnected() {
        if (this.configuration == null) {
            configureHarvester(HarvestConfiguration.getDefaultHarvestConfiguration());
        }
        if (this.harvestData.isValid()) {
            this.log.verbose("Skipping connect call, saved state is available: " + this.harvestData.getDataToken());
            StatsEngine.get().sample("Session/Start", 1.0f);
            fireOnHarvestConnected();
            transition(State.CONNECTED);
            execute();
            return;
        }
        this.log.info("Connecting, saved state is not available: " + this.harvestData.getDataToken());
        HarvestResponse response = this.harvestConnection.sendConnect();
        if (response == null) {
            this.log.error("Unable to connect to the Collector.");
        } else if (response.isOK()) {
            HarvestConfiguration configuration = parseHarvesterConfiguration(response);
            if (configuration == null) {
                this.log.error("Unable to configure Harvester using Collector configuration.");
                return;
            }
            configureHarvester(configuration);
            StatsEngine.get().sampleTimeMs("Supportability/AgentHealth/Collector/Harvest", response.getResponseTime());
            fireOnHarvestConnected();
            transition(State.CONNECTED);
        } else {
            this.log.debug("Harvest connect response: " + response.getResponseCode());
            switch (response.getResponseCode()) {
                case UNAUTHORIZED:
                case INVALID_AGENT_ID:
                    this.harvestData.getDataToken().clear();
                    fireOnHarvestDisconnected();
                    return;
                case FORBIDDEN:
                    if (!response.isDisableCommand()) {
                        this.log.error("Unexpected Collector response: FORBIDDEN");
                        break;
                    }
                    this.log.error("Collector has commanded Agent to disable.");
                    fireOnHarvestDisabled();
                    transition(State.DISABLED);
                    return;
                case UNSUPPORTED_MEDIA_TYPE:
                case ENTITY_TOO_LARGE:
                    this.log.error("Invalid ConnectionInformation was sent to the Collector.");
                    break;
                default:
                    this.log.error("An unknown error occurred when connecting to the Collector.");
                    break;
            }
            fireOnHarvestError();
        }
    }

    protected void connected() {
        this.log.info("Harvester: connected");
        this.log.info("Harvester: Sending " + this.harvestData.getHttpTransactions().count() + " HTTP transactions.");
        this.log.info("Harvester: Sending " + this.harvestData.getHttpErrors().count() + " HTTP errors.");
        this.log.info("Harvester: Sending " + this.harvestData.getActivityTraces().count() + " activity traces.");
        this.harvestData.setAnalyticsEnabled(this.agentConfiguration.getEnableAnalyticsEvents());
        if (this.agentConfiguration.getEnableAnalyticsEvents() && FeatureFlag.featureEnabled(FeatureFlag.AnalyticsEvents)) {
            EventManager eventManager = AnalyticsControllerImpl.getInstance().getEventManager();
            if (eventManager.isTransmitRequired()) {
                Set sessionAttributes = new HashSet();
                sessionAttributes.addAll(AnalyticsControllerImpl.getInstance().getSystemAttributes());
                sessionAttributes.addAll(AnalyticsControllerImpl.getInstance().getUserAttributes());
                this.harvestData.setSessionAttributes(sessionAttributes);
                this.log.info("Harvester: Sending " + this.harvestData.getSessionAttributes().size() + " session attributes.");
                this.harvestData.setAnalyticsEvents(eventManager.getQueuedEvents());
                eventManager.empty();
            }
            this.log.info("Harvester: Sending " + this.harvestData.getAnalyticsEvents().size() + " analytics events.");
        }
        HarvestResponse response = this.harvestConnection.sendData(this.harvestData);
        if (response == null || response.isUnknown()) {
            fireOnHarvestSendFailed();
            return;
        }
        this.harvestData.reset();
        StatsEngine.get().sampleTimeMs("Supportability/AgentHealth/Collector/Harvest", response.getResponseTime());
        this.log.debug("Harvest data response: " + response.getResponseCode());
        this.log.debug("Harvest data response status code: " + response.getStatusCode());
        this.log.debug("Harvest data response BODY: " + response.getResponseBody());
        if (response.isError()) {
            fireOnHarvestError();
            switch (response.getResponseCode()) {
                case UNAUTHORIZED:
                case INVALID_AGENT_ID:
                    this.harvestData.getDataToken().clear();
                    transition(State.DISCONNECTED);
                    return;
                case FORBIDDEN:
                    if (response.isDisableCommand()) {
                        this.log.error("Collector has commanded Agent to disable.");
                        transition(State.DISABLED);
                        return;
                    }
                    this.log.error("Unexpected Collector response: FORBIDDEN");
                    transition(State.DISCONNECTED);
                    return;
                case UNSUPPORTED_MEDIA_TYPE:
                case ENTITY_TOO_LARGE:
                    this.log.error("Invalid ConnectionInformation was sent to the Collector.");
                    return;
                default:
                    this.log.error("An unknown error occurred when connecting to the Collector.");
                    return;
            }
        }
        HarvestConfiguration configuration = parseHarvesterConfiguration(response);
        if (configuration == null) {
            this.log.error("Unable to configure Harvester using Collector configuration.");
            return;
        }
        configureHarvester(configuration);
        fireOnHarvestComplete();
    }

    protected void disabled() {
        Harvest.stop();
        fireOnHarvestDisabled();
    }

    protected void execute() {
        this.log.debug("Harvester state: " + this.state);
        this.stateChanged = false;
        try {
            expireHarvestData();
            switch (this.state) {
                case UNINITIALIZED:
                    uninitialized();
                    return;
                case DISCONNECTED:
                    fireOnHarvestBefore();
                    disconnected();
                    return;
                case CONNECTED:
                    fireOnHarvestBefore();
                    fireOnHarvest();
                    fireOnHarvestFinalize();
                    TaskQueue.synchronousDequeue();
                    connected();
                    return;
                case DISABLED:
                    disabled();
                    return;
                default:
                    throw new IllegalStateException();
            }
        } catch (Exception e) {
            this.log.error("Exception encountered while attempting to harvest", e);
            AgentHealth.noticeException(e);
        }
       /* this.log.error("Exception encountered while attempting to harvest", e);
        AgentHealth.noticeException(e);*/
    }

    protected void transition(State newState) {
        if (this.stateChanged) {
            this.log.debug("Ignoring multiple transition: " + newState);
        } else if (this.state != newState) {
            switch (this.state) {
                case UNINITIALIZED:
                    if (!stateIn(newState, State.DISCONNECTED, newState, State.CONNECTED, State.DISABLED)) {
                        throw new IllegalStateException();
                    }
                    break;
                case DISCONNECTED:
                    if (!stateIn(newState, State.UNINITIALIZED, State.CONNECTED, State.DISABLED)) {
                        throw new IllegalStateException();
                    }
                    break;
                case CONNECTED:
                    if (!stateIn(newState, State.DISCONNECTED, State.DISABLED)) {
                        throw new IllegalStateException();
                    }
                    break;
                default:
                    throw new IllegalStateException();
            }
            changeState(newState);
        }
    }

    private HarvestConfiguration parseHarvesterConfiguration(HarvestResponse response) {
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.registerTypeAdapter(ActivityTraceConfiguration.class, new ActivityTraceConfigurationDeserializer());
        HarvestConfiguration config = null;
        try {
            return (HarvestConfiguration) gsonBuilder.create().fromJson(response.getResponseBody(), HarvestConfiguration.class);
        } catch (Exception e) {
            this.log.error("Unable to parse collector configuration: " + e.getMessage());
            AgentHealth.noticeException(e);
            return config;
        }
    }

    private void configureHarvester(HarvestConfiguration harvestConfiguration) {
        this.configuration.reconfigure(harvestConfiguration);
        this.harvestData.setDataToken(this.configuration.getDataToken());
        Harvest.setHarvestConfiguration(this.configuration);
    }

    private void changeState(State newState) {
        this.log.debug("Harvester changing state: " + this.state + " -> " + newState);
        if (this.state == State.CONNECTED) {
            if (newState == State.DISCONNECTED) {
                fireOnHarvestDisconnected();
            } else if (newState == State.DISABLED) {
                fireOnHarvestDisabled();
            }
        }
        this.state = newState;
        this.stateChanged = true;
    }

    private boolean stateIn(State testState, State... legalStates) {
        for (State state : legalStates) {
            if (testState == state) {
                return true;
            }
        }
        return false;
    }

    public State getCurrentState() {
        return this.state;
    }

    public boolean isDisabled() {
        return State.DISABLED == this.state;
    }

    public void addHarvestListener(HarvestLifecycleAware harvestAware) {
        if (harvestAware == null) {
            this.log.error("Can't add null harvest listener");
            new Exception().printStackTrace();
            return;
        }
        synchronized (this.harvestListeners) {
            if (this.harvestListeners.contains(harvestAware)) {
                return;
            }
            this.harvestListeners.add(harvestAware);
        }
    }

    public void removeHarvestListener(HarvestLifecycleAware harvestAware) {
        synchronized (this.harvestListeners) {
            if (this.harvestListeners.contains(harvestAware)) {
                this.harvestListeners.remove(harvestAware);
                return;
            }
        }
    }

    public void expireHarvestData() {
        expireHttpErrors();
        expireHttpTransactions();
        expireActivityTraces();
    }

    public void expireHttpErrors() {
        HttpErrors errors = this.harvestData.getHttpErrors();
        synchronized (errors) {
            Collection oldErrors = new ArrayList();
            long now = System.currentTimeMillis();
            long maxAge = this.configuration.getReportMaxTransactionAgeMilliseconds();
            for (HttpError error : errors.getHttpErrors()) {
                if (error.getTimestamp().longValue() < now - maxAge) {
                    this.log.debug("HttpError too old, purging: " + error);
                    oldErrors.add(error);
                }
            }
            for (HttpError error2 : oldErrors) {
                errors.removeHttpError(error2);
            }
        }
    }

    public void expireHttpTransactions() {
        HttpTransactions transactions = this.harvestData.getHttpTransactions();
        synchronized (transactions) {
            Collection oldTransactions = new ArrayList();
            long now = System.currentTimeMillis();
            long maxAge = this.configuration.getReportMaxTransactionAgeMilliseconds();
            for (HttpTransaction txn : transactions.getHttpTransactions()) {
                if (txn.getTimestamp().longValue() < now - maxAge) {
                    this.log.debug("HttpTransaction too old, purging: " + txn);
                    oldTransactions.add(txn);
                }
            }
            for (HttpTransaction txn2 : oldTransactions) {
                transactions.remove(txn2);
            }
        }
    }

    public void expireActivityTraces() {
        ActivityTraces traces = this.harvestData.getActivityTraces();
        synchronized (traces) {
            Collection expiredTraces = new ArrayList();
            long maxAttempts = (long) this.configuration.getActivity_trace_max_report_attempts();
            for (ActivityTrace trace : traces.getActivityTraces()) {
                if (trace.getReportAttemptCount() >= maxAttempts) {
                    this.log.debug("ActivityTrace has had " + trace.getReportAttemptCount() + " report attempts, purging: " + trace);
                    expiredTraces.add(trace);
                }
            }
            for (ActivityTrace trace2 : expiredTraces) {
                traces.remove(trace2);
            }
        }
    }

    public void setAgentConfiguration(AgentConfiguration agentConfiguration) {
        this.agentConfiguration = agentConfiguration;
    }

    public void setHarvestConnection(HarvestConnection connection) {
        this.harvestConnection = connection;
    }

    public HarvestConnection getHarvestConnection() {
        return this.harvestConnection;
    }

    public void setHarvestData(HarvestData harvestData) {
        this.harvestData = harvestData;
    }

    public HarvestData getHarvestData() {
        return this.harvestData;
    }

    private void fireOnHarvestBefore() {
        try {
            for (HarvestLifecycleAware harvestAware : getHarvestListeners()) {
                harvestAware.onHarvestBefore();
            }
        } catch (Exception e) {
            this.log.error("Error in fireOnHarvestBefore", e);
            AgentHealth.noticeException(e);
        }
    }

    private void fireOnHarvestStart() {
        try {
            for (HarvestLifecycleAware harvestAware : getHarvestListeners()) {
                harvestAware.onHarvestStart();
            }
        } catch (Exception e) {
            this.log.error("Error in fireOnHarvestStart", e);
            AgentHealth.noticeException(e);
        }
    }

    private void fireOnHarvestStop() {
        try {
            for (HarvestLifecycleAware harvestAware : getHarvestListeners()) {
                harvestAware.onHarvestStop();
            }
        } catch (Exception e) {
            this.log.error("Error in fireOnHarvestStop", e);
            AgentHealth.noticeException(e);
        }
    }

    private void fireOnHarvest() {
        try {
            for (HarvestLifecycleAware harvestAware : getHarvestListeners()) {
                harvestAware.onHarvest();
            }
        } catch (Exception e) {
            this.log.error("Error in fireOnHarvest", e);
            AgentHealth.noticeException(e);
        }
    }

    private void fireOnHarvestFinalize() {
        try {
            for (HarvestLifecycleAware harvestAware : getHarvestListeners()) {
                harvestAware.onHarvestFinalize();
            }
        } catch (Exception e) {
            this.log.error("Error in fireOnHarvestFinalize", e);
            AgentHealth.noticeException(e);
        }
    }

    private void fireOnHarvestDisabled() {
        try {
            for (HarvestLifecycleAware harvestAware : getHarvestListeners()) {
                harvestAware.onHarvestDisabled();
            }
        } catch (Exception e) {
            this.log.error("Error in fireOnHarvestDisabled", e);
            AgentHealth.noticeException(e);
        }
    }

    private void fireOnHarvestDisconnected() {
        try {
            for (HarvestLifecycleAware harvestAware : getHarvestListeners()) {
                harvestAware.onHarvestDisconnected();
            }
        } catch (Exception e) {
            this.log.error("Error in fireOnHarvestDisconnected", e);
            AgentHealth.noticeException(e);
        }
    }

    private void fireOnHarvestError() {
        try {
            for (HarvestLifecycleAware harvestAware : getHarvestListeners()) {
                harvestAware.onHarvestError();
            }
        } catch (Exception e) {
            this.log.error("Error in fireOnHarvestError", e);
            AgentHealth.noticeException(e);
        }
    }

    private void fireOnHarvestSendFailed() {
        try {
            for (HarvestLifecycleAware harvestAware : getHarvestListeners()) {
                harvestAware.onHarvestSendFailed();
            }
        } catch (Exception e) {
            this.log.error("Error in fireOnHarvestSendFailed", e);
            AgentHealth.noticeException(e);
        }
    }

    private void fireOnHarvestComplete() {
        try {
            for (HarvestLifecycleAware harvestAware : getHarvestListeners()) {
                harvestAware.onHarvestComplete();
            }
        } catch (Exception e) {
            this.log.error("Error in fireOnHarvestComplete", e);
            AgentHealth.noticeException(e);
        }
    }

    private void fireOnHarvestConnected() {
        try {
            for (HarvestLifecycleAware harvestAware : getHarvestListeners()) {
                harvestAware.onHarvestConnected();
            }
        } catch (Exception e) {
            this.log.error("Error in fireOnHarvestConnected", e);
            AgentHealth.noticeException(e);
        }
    }

    public void setConfiguration(HarvestConfiguration configuration) {
        this.configuration = configuration;
    }

    private Collection getHarvestListeners() {
        return new ArrayList(this.harvestListeners);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy