io.monalabs.client.MonaClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mona-java-client Show documentation
Show all versions of mona-java-client Show documentation
A client for exporting data to Mona servers.
package io.monalabs.client;
/*-
* #%L
* mona-java-client
* %%
* Copyright (C) 2019 Mona Labs
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.komamitsu.fluency.Fluency;
import org.komamitsu.fluency.fluentd.FluencyBuilderForFluentd;
import java.io.Closeable;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Logger;
/**
* The default implementation for a Mona java client.
*/
public class MonaClient implements Closeable {
private final static String MONA_ARC_CLASS_FIELD_NAME = "MONA_ARC_CLASS";
private final static Logger LOGGER = Logger.getLogger(MonaClient.class.getName());
/**
* The client to communicate with Mona's fluentd on Mona's servers.
*/
private final Fluency fluency;
/**
* A user id to be added to any message sent to Mona, for identification purposes.
*/
private final String monaUserId;
protected MonaClient(Fluency fluency, String monaUserId) {
this.fluency = fluency;
this.monaUserId = monaUserId;
}
private MonaClient(Builder builder) {
FluencyBuilderForFluentd fluencyBuilder = new FluencyBuilderForFluentd();
fluencyBuilder.setBufferChunkInitialSize(builder.bufferChunkInitialSize);
fluencyBuilder.setBufferChunkRetentionSize(builder.bufferChunkRetentionSize);
fluencyBuilder.setMaxBufferSize(builder.maxBufferSize);
fluencyBuilder.setFlushIntervalMillis(builder.flushIntervalMillis);
fluencyBuilder.setSslEnabled(true);
fluencyBuilder.setErrorHandler(e -> {
LOGGER.warning(String.format("Error sending data to Mona: %s", e.getMessage()));
});
fluencyBuilder.setAckResponseMode(builder.ackResponseMode);
fluencyBuilder.setConnectionTimeoutMilli(builder.connectionTimeoutMilli);
fluencyBuilder.setReadTimeoutMilli(builder.readTimeoutMilli);
fluencyBuilder.setSenderMaxRetryCount(builder.senderMaxRetryCount);
this.fluency = fluencyBuilder.build(builder.host, builder.port);
this.monaUserId = builder.monaUserId;
}
/**
* Closes the inner connection socket to Mona's fluentd.
*/
@Override
public void close() {
try {
fluency.close();
} catch (Exception e) {
LOGGER.warning(String.format("IO Exception when closing link to fluentd: %s", e.getMessage()));
}
}
public long getCurrentUnsentDataSize() {
return this.fluency.getBufferedDataSize();
}
private int amountOfDotsInString(String checkedString) {
return checkedString.length() - checkedString.replace(".", "").length();
}
/**
* The main exporting mechanism. Use this method, or any of its variants, to send context-free messages to Mona's
* system.
*
* @param arcClass A tag for the ARC class that will be sent using this exportStandalone method. Mona uses ARC
* classes to know which arcs belong together and should be compared. See Readme for explanation
* about ARCs. This string can have dots, which allows the use of sub-ARC-classes.
* @param contextId The ID to use for this context. Can be empty or null, in which case the client will create a
* random UUID as the context id.
* When using sub-ARCs (i.e., when the given arcClass param has dots in it), the context id may
* also contain dots (at most the amount of dots in the arcClass param), to infer the context
* ids for each sub-ARC.
* @param message A json-like object consisting of the actual message to send to Mona.
*/
public void exportStandalone(String arcClass, String contextId, Map message) {
if (message == null) {
LOGGER.warning("Tried to export null message");
return;
}
if (message.isEmpty()) {
// Never send empty messages.
LOGGER.warning("Tried to export empty message");
return;
}
if (arcClass == null || arcClass.isEmpty()) {
// Don't allow empty arc classes
LOGGER.warning("Tried to export with empty ARC class");
return;
}
if (arcClass.endsWith(".")) {
LOGGER.warning("ARC classes cannot end with dots");
return;
}
// Context specific checks.
if (contextId == null) {
// Avoid handling null values.
contextId = "";
}
if (contextId.endsWith(".")) {
LOGGER.warning("Context ids cannot end with dots");
return;
}
int missingContextIdsCount = amountOfDotsInString(arcClass) - amountOfDotsInString(contextId);
if (missingContextIdsCount < 0) {
LOGGER.warning("Tried to export a context ID with more sub-contexts than in the given ARC class.");
return;
}
// We allow the user to only supply context ids for a prefix of the arc class, and add context ids to the
// suffix as required. This allows the user to know of a specific top context, but not to care about the ids
// of sub contexts.
StringBuilder contextBuilder = new StringBuilder().append(contextId);
for (int i = 0; i < missingContextIdsCount; ++i) {
contextBuilder.append(".");
contextBuilder.append(UUID.randomUUID().toString());
}
contextId = contextBuilder.toString();
Map output_inner_message = new HashMap<>(message);
output_inner_message.put(MONA_ARC_CLASS_FIELD_NAME, arcClass);
Map outerMessage = new HashMap<>();
outerMessage.put("user_id", monaUserId);
outerMessage.put("context", contextId);
outerMessage.put("message", output_inner_message);
outerMessage.put("export_timestamp", Instant.now().getEpochSecond());
try {
fluency.emit("mona.client.message", outerMessage);
} catch (Exception e) {
LOGGER.warning(String.format("IO Exception when emitting to fluentd: %s", e.getMessage()));
}
}
/**
* Shorthand for the above exportStandalone variant, leaving the contextId empty.
*/
public void exportStandalone(String arcClass, Map message) {
exportStandalone(arcClass, "", message);
}
/**
* Use this exportStandalone variant to send a batch (list) of unrelated messages to Mona. Each message in the
* list will receive its own random context.
*
* @param messages a list of json-like messages to send to Mona
*/
public void exportStandalone(String arcClass, List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy