keenlabs / keenclient-java Goto Github PK
View Code? Open in Web Editor NEWOfficial Java client for the Keen IO API. Build analytics features directly into your Java apps.
Home Page: https://keen.io/docs
License: MIT License
Official Java client for the Keen IO API. Build analytics features directly into your Java apps.
Home Page: https://keen.io/docs
License: MIT License
I was testing the API in our application server and it seems the java client doesn't support Java 6. Is there any good reason not to support Java 6?. There are still a lot of Java 6 code out there
Thanks.
Not sure if you'd call this a bug, but it was surprising to me when I ran into it...
If your global properties has key keen
then anything supplied in the event's keenProperties parameter will be ignored.
I ran into this when setting keen.timestamp
with a global properties evaluator. That prevented me from sending keen.addons
or keen.location.coordinates
with my events. It was surprising because there was no error/warning to indicate that something was being discarded. Everything looked OK on the sender, but the events were showing up incomplete in keen.
Thanks!
We're seeing this issue in our app. The KeenClient creates the ExecutorService which keeps threads alive and prevents Tomcat from shutting down.
There is some discussion about the issue here:
http://stackoverflow.com/questions/12815614/shutdown-executorservice-gracefully-in-webapp
I believe there should be a method on KeenClient to shutdown and await termination of the executor service. That would push the burden onto the user, but would allow any situation to be catered for.
Perhaps it would be possible to annotate the class with "@weblistener" as per these instructions http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContextListener.html#contextDestroyed%28javax.servlet.ServletContextEvent%29 and to then implement the ServletContextListener. However this would introduce a dependency on the servlet api. Perhaps you could create a new subclass of KeenClient called KeenWebClient which did that?
I'm happy to contribute a pull request. I'm just not sure of the best approach :-)
We are having some issues with the Keen.io java client we are pushing a lot of events. those event are leagcy event and we are overriding the timestamp value of each event. We using the addEventAsync() method.
what we observed is that under load this does not work as expected and events are dropped.
protected Executor getDefaultPublishExecutor() throws Exception {
int procCount = Runtime.getRuntime().availableProcessors();
return Executors.newFixedThreadPool(procCount);
}
which returns a instances of ThreadPoolExecutor as per
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
}
We think the TreadPoolExecutor implementation drops requests when all the threads are busy doing pushing event to keen.io
We cannot use sendQueuedEventsAsync() as we need to control the timestamp value of the events ?
I don't really understand (didn't look into it) why we cannot specified (override) the timestamp of the events when queuing them ?
any other suggestion on how we could this ?
Keen crashes my app shortly after launch with this error.
java.lang.RuntimeException: java.net.ConnectException: failed to connect to api.keen.io/127.0.0.1 (port 443) after 30000ms: isConnected failed: ECONNREFUSED (Connection refused)
at io.keen.client.java.KeenClient.handleFailure(KeenClient.java:1617)
at io.keen.client.java.KeenClient.addEvent(KeenClient.java:166)
at io.keen.client.java.KeenClient$1.run(KeenClient.java:233)
After some digging around, I found that api.keen.io is in an ad-block hosts file commonly used with Android AdBlockers, such as AdAway. I added the hostname to the whitelist and the crash goes away, but it probably shouldn't be crashing in the first place. Not to mention the end user won't be so willing to add that to their whitelist (if they even know how to in the first place)
The RelativeTimeframe class currently has default access making it impossible to use from different packages. It should be a public class.
The artifact io.keen:keen-client-api-android:5.0.0
hosted on central Maven or JCenter does not bring the transitive dependency to io.keen:keen-client-java-core:5.0.0
although this library needs to be present as well.
It seems this is a bug with the published artifacts, since the README states that transitive dependencies should be present.
The JacksonJsonHandler class has default access modifier, making it impossible to instanciate it from other packages. It might be useful to have an instance of this class in certain situations, such as when creating integrations with other technologies. If this issue is accepted, the constructor should be also made public.
This class is not used; io.keen.client.java.KeenLogging handles all logging functionality. The existence of the Android class is confusing though. It should just be deleted.
It looks like the Scoped Key structure has changed. The master keys were 32 characters long, but the newer projects have 64 character master keys. This may have been modified in other libraries but does not appear to have been updated in the JS library yet.
This was noticed when a customer began receiving an InvalidKeyException error while attempting to encrypt using the new master API key.
In order to deal with HTTP responses that can contain either a root JSON Object or a root JSON Array, at a low level we have to check the structure and either return a Map<>
or a List<>
. That fundamentally changes some of the core code across the SDK, so we added __fake_root
to circumvent this without a breaking change.
Look at addressing this in a better way with a breaking change for the next major version bump.
Here is the code I am using to add location coordinates to the Keen Properties.
double[] coordinates = {37.5793,-122.3164}; // new Double[2];
Map<String, Object> keenProperties = new HashMap<String, Object>();
Map<String, Object> keenLocationProperties = new HashMap<String, Object>();
keenLocationProperties.put("coordinates",coordinates );
keenProperties.put("location", keenLocationProperties);
KeenClient.client().queueEvent("activityEvents", newActivityEvent.toKeenHashMap(sequenceNumber, mPrefs.getString("tag", ""),uuid),keenProperties);
When using the above code on Nexus 5, the keen.location.coordinates property looks correct and the data is uploaded to Keen successfully.
However, when running on the Samsung Galaxy S3 the keen.location.coordinates property does not format as an array. The data does not upload to Keen - I get an error message Invalidpropertyvalueerror in the return JSON from Keen.
The bug I found is a NullPointerException on line 318 of KeenClient.java. Working backwards, that means that getKeenCacheSubDirectories() returns null, which happens because getKeenCacheDirectory() returns an invalid directory.
To fix the bug, I run the following code before calling KeenClient.upload():
java.io.File keenDir = new java.io.File(context.getCacheDir(), "keen");
if(!keenDir.exists()) {
keenDir.mkdir();
}
Since the API does allow for a given property to be null
and pass an exists
filter with a value of true
, and of course a property can have the string value 'null'
, there is a meaningful distinction here that needs to be addressed.
See here where we can fix this and add tests.
Note that the .NET SDK has the same bug.
We could be more explicit about which filters are actually nullable and proactively warn client code with exceptions if trying to, say, set the property_value
to null
for an exists
filter when only true
and false
are acceptable values. However, we don't do any of that type of validation right now on the Filter.propertyValue
so that might be out of scope, and at a minimum we should accept null
.
I'm using latest KeenClient in an Android app and the follwoing lgos keep appering :
07-04 08:10:04.925 7491-8567/io.gresse.hugo.anecdote W/art: Long monitor contention event with owner method=java.lang.String io.a.a.b.g.a(io.a.a.b.q, java.net.URL, java.util.Map) from KeenClient.java:1389 waiters=2 for 1.328s
07-04 08:10:05.574 7491-8574/io.gresse.hugo.anecdote W/art: Long monitor contention event with owner method=java.lang.String io.a.a.b.g.a(io.a.a.b.q, java.net.URL, java.util.Map) from KeenClient.java:1389 waiters=1 for 1.192s
07-04 08:10:06.287 7491-7513/io.gresse.hugo.anecdote W/art: Long monitor contention event with owner method=java.lang.String io.a.a.b.g.a(io.a.a.b.q, java.net.URL, java.util.Map) from KeenClient.java:1389 waiters=1 for 1.264s
07-04 08:10:07.002 7491-8509/io.gresse.hugo.anecdote W/art: Long monitor contention event with owner method=java.lang.String io.a.a.b.g.a(io.a.a.b.q, java.net.URL, java.util.Map) from KeenClient.java:1389 waiters=1 for 1.422s
07-04 08:10:09.039 7491-8567/io.gresse.hugo.anecdote W/art: Long monitor contention event with owner method=java.lang.String io.a.a.b.g.a(io.a.a.b.q, java.net.URL, java.util.Map) from KeenClient.java:1389 waiters=1 for 2.508s
07-04 08:10:09.758 7491-8574/io.gresse.hugo.anecdote W/art: Long monitor contention event with owner method=java.lang.String io.a.a.b.g.a(io.a.a.b.q, java.net.URL, java.util.Map) from KeenClient.java:1389 waiters=0 for 641ms
07-04 08:11:26.995 7491-8509/io.gresse.hugo.anecdote W/art: Long monitor contention event with owner method=java.lang.String io.a.a.b.g.a(io.a.a.b.q, java.net.URL, java.util.Map) from KeenClient.java:1389 waiters=0 for 499ms
07-04 08:11:27.650 7491-8567/io.gresse.hugo.anecdote W/art: Long monitor contention event with owner method=java.lang.String io.a.a.b.g.a(io.a.a.b.q, java.net.URL, java.util.Map) from KeenClient.java:1389 waiters=1 for 971ms
07-04 08:11:28.910 7491-8574/io.gresse.hugo.anecdote W/art: Long monitor contention event with owner method=java.lang.String io.a.a.b.g.a(io.a.a.b.q, java.net.URL, java.util.Map) from KeenClient.java:1389 waiters=2 for 2.045s
It seems to appear very often...
We should work on making it easier to do lower-level validation of HTTP requests in the query tests. KeenQueryTestBase
might be a good place to share this functionality since this is where we have the shared code to mock and capture requests and responses.
From PR #96:
// TODO : Add a means to check more about the lower-level HTTP request, like the specific
// headers, URL, response codes, etc. Both the DELETE and GET requests have no request body
// so everything is in the URL/headers. KeenQueryTest does this in some places.
...and...
// TODO : We should add some verification of the actual URL produced in the Request
// the way we do in some of the tests in KeenQueryTest.
Using version 2.0.3 I am able to get the SDK "stuck" on an empty event file by doing the following:
Result: org.json.JSONException: End of input at character 0 of
from an empty file in the cache. It has a filename that is a current timestamp, so my guess is that the file system has issues when quitting the emulator that cause it to not properly flush the filesystem.
I don't have an Android device on me right now, so I can't verify whether this is purely an emulator issue of is a problem with our SDK.
The KeenClient for java registers its own log handler to publish logs to System.out. It would be useful to have a clean way to disable this default handler to meet application needs.
For instance, some applications may prefer to have Keen log to a file and reserve System.out for warning or error messages.
I would suggest additions to the KeenLogging class to allow the application to disable the default handler that is registered by Keen. If you feel that this would be valuable, I can put together a PR for this.
(UPDATED POST)
I originally posted here on 9/30 regarding a problem sending events to Keen using the Java SDK, in which I was experiencing the following error logs (note: the SDK error message does not make sense, since the Json in question is valid)
FINER: Adding event to collection: SillyCollection
Sep 30, 2015 1:42:03 PM io.keen.client.java.KeenLogging log
FINER: Sent request '{"keen":{"timestamp":"2015-08-05T21:34:12.290Z"},"name":"Silly Name","id":123,"user":{"role":"user","id":9111,"class_role":"student"}}' to URL 'https://api.keen.io/3.0/projects/55ef2fa159949a355159a02c/events/SillyCollection'
Sep 30, 2015 1:42:03 PM io.keen.client.java.KeenLogging log
FINER: Received response: '{"message": "The specified JSON is invalid. No JSON object could be decoded", "error_code": "InvalidJSONError"}' (400)
After further experimentation, turns out that Keen does not return an error when the default json serializer/deserializer (that is, jackson) is used instead of my choice (flexjson). Interestingly enough, the json produced by the default, and my replacement one, seem to be exactly the same -according to the Keen logger. This suggests that there may be a problem on your end that causes the json to be rejected as invalid.
Here's the output when I use Jackson:
FINER: Sent request '{"keen":{"timestamp":"2015-08-05T21:34:12.290Z"},"name":"Silly Name","id":123,"user":{"role":"user","id":9111,"class_role":"student"}}' to URL 'https://api.keen.io/3.0/projects/55ef2fa159949a355159a02c/events/SillyCollection'
Oct 05, 2015 1:58:22 PM io.keen.client.java.KeenLogging log
FINER: Received response: '{"created": true}' (201)
And here's the output when I use MyKeenJsonHandler (which I include below) instead:
FINER: Sent request '{"keen":{"timestamp":"2015-08-05T21:34:12.290Z"},"name":"Silly Name","id":123,"user":{"role":"user","id":9111,"class_role":"student"}}' to URL 'https://api.keen.io/3.0/projects/55ef2fa159949a355159a02c/events/SillyCollection'
Oct 05, 2015 2:03:02 PM io.keen.client.java.KeenLogging log
FINER: Received response: '{"message": "The specified JSON is invalid. No JSON object could be decoded", "error_code": "InvalidJSONError"}' (400)
Oct 05, 2015 2:03:02 PM io.keen.client.java.KeenLogging log
FINER: Encountered error: {"message": "The specified JSON is invalid. No JSON object could be decoded", "error_code": "InvalidJSONError"}
Here's my json handler code for your inspection:
File: MyKeenJsonHandler.java (defines a Json handler that uses flexjson)
package edu.northwestern.at.yellowdig.process.test;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.Map;
import flexjson.JSONDeserializer;
import flexjson.JSONSerializer;
import io.keen.client.java.KeenJsonHandler;
public class MyKeenJsonHandler implements KeenJsonHandler {
@Override
public Map<String, Object> readJson(Reader arg0) throws IOException {
Map<String, Object> result = new JSONDeserializer<Map<String, Object>>().deserialize(arg0);
return result;
}
@Override
public void writeJson(Writer arg0, Map<String, ?> arg1) throws IOException {
new JSONSerializer().exclude("*.class").deepSerialize(arg1, arg0);
}
}
A user noticed a performance issue when sending events and I'm adding it here for visibility as we track this down:
I drilled down a bit in my test and I found something strange: my (Java) code seems to spend more time in queueing events queueEvents(…) than in sendQueuedEvents(…)
Below a short excerpt, times are in milliseconds:
Queuing time: 6645 Sending time: 13501
0-0 Total events: 4999 Total time: 20146 Events per second: 248.1385883053708
Queuing time: 14183 Sending time: 6875
1-0 Total events: 9998 Total time: 41205 Events per second: 242.64045625530883
Queuing time: 40750 Sending time: 6045
2-0 Total events: 14997 Total time: 88000 Events per second: 170.42045454545453
Queuing time: 69652 Sending time: 5736
3-0 Total events: 19996 Total time: 163388 Events per second: 122.38352877812324
Queuing time: 86217 Sending time: 5985
4-0 Total events: 24995 Total time: 255590 Events per second: 97.79334089753121
My test was using only one thread – so I guess. I looked at the memory usage – it seems almost constant during the test – so a memory leak is unlikely.
There seems to be a degradation in performance in one the internal collections of the Keen Java library, with every call to it.
I assumed that the KeenClient.client().sendQueuedEvents() method also clears the queue after serializing it and I did not find any clear method.
As a note, I’m using the latest Keen Java SDK, 2.1.1
In KeenClient.java
the validateEvent
throws an error if the event is null or empty.
If I have set some global properties and want to simply add an event to my collection without adding any extra attributes. How am I supposed to do that?
Thanks
Timeout trying to send data to keen.
http://cl.ly/091g452B1Z0P?_ga=1.182769446.1852350949.1425422880
X-Eon-Dm: dm0208
Return-Path: 0000014be12a234e-ade75f62-a273-496d-95d9-3a71c3be2bbe-000000@amazonses.com
Received: from a8-38.smtp-out.amazonses.com (a8-38.smtp-out.amazonses.com [54.240.8.38])
by dm0208.mta.everyone.net (EON-INBOUND) with ESMTP id dm0208.54ed0dd6.dd899c
for [email protected]; Tue, 3 Mar 2015 11:43:32 -0800
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple;
s=224i4yxa5dv7c2xz3womw6peuasteono; d=amazonses.com; t=1425411810;
h=Date:From:To:Message-ID:Subject:Mime-Version:Content-Type:Content-Transfer-Encoding:Feedback-ID;
bh=C1X+rQFbnqicGW8ZjCXNFWiKwgPnbgKMkgQ/b5lEE24=;
b=J0PCVgiQ5uyd2v5wQkepF1ZgQGLcgd2RDw+QXCi7nEmUhw1z5t6Gi2Rr1cITyHpu
1yTZl5XHNFEFWLR8OSGtUXlbaVQAszwu6vBXTzTklcEhsecrjUIOhUX7uPMhbkmh4C7
7EbLxxTS32TVOZRNIWU62NAVelbBSDn6vfWTQoy8=
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple;
s=jivsh7bfp4m6jigp3jpzsonmbsz3s7dl; d=hockeyapp.net; t=1425411810;
h=Date:From:To:Message-ID:Subject:Mime-Version:Content-Type:Content-Transfer-Encoding;
bh=C1X+rQFbnqicGW8ZjCXNFWiKwgPnbgKMkgQ/b5lEE24=;
b=Sd44VKggBdc6mgicuo0u3POL1+D9Q9A1D/llHJlhWP4zjAEVC9kWttugb3FJwO02
TL4e4hQvybs4WyrhpKbeIattnXsyP5TPK34/UDiaT1szr09PfWRmncW05TW7gFfYLa7
VCN9JnzsZbgM9q6LHt987g7s7s8rjbqNebcTdfTE=
Date: Tue, 3 Mar 2015 19:43:30 +0000
From: HockeyApp [email protected]
To: [email protected]
Message-ID: 0000014be12a234e-ade75f62-a273-496d-95d9-3a71c3be2bbe-000000@email.amazonses.com
Subject: New Crash Group for huedoku 1.1 (5)
Mime-Version: 1.0
Content-Type: multipart/alternative;
boundary="--==_mimepart_54f60ee2cde1_46fff2e0f4730e3";
charset=UTF-8
Content-Transfer-Encoding: 7bit
X-SES-Outgoing: 2015.03.03-54.240.8.38
Feedback-ID: 1.us-east-1.oTMZEeVd2+LMait86PfB2/S1KcIyX4fprYdxw8oBSqU=:AmazonSES
Sender: 0000014be12a234e-ade75f62-a273-496d-95d9-3a71c3be2bbe-000000@amazonses.com
----==_mimepart_54f60ee2cde1_46fff2e0f4730e3
Content-Type: text/plain;
charset=UTF-8
Content-Transfer-Encoding: 7bit
HockeyApp created a new crash group for this app:
huedoku 1.1 (5)
Reason:
java.lang.RuntimeException: java.net.ConnectException: failed to connect to api.keen.io/108.168.254.131 (port 443) after 30000ms: connect failed: ENETUNREACH (Network is unreachable)
Location:
io.keen.client.java.KeenClient.handleFailure, line 1345
View on HockeyApp:
https://rink.hockeyapp.net/manage/apps/103879/crash_reasons/29510737?no_iphone_ui=true
If you have any questions, please contact us at [email protected] or support.hockeyapp.net.
----==_mimepart_54f60ee2cde1_46fff2e0f4730e3
Content-Type: text/html;
charset=UTF-8
Content-Transfer-Encoding: 7bit
HockeyApp created a new crash group.
Reason:
java.lang.RuntimeException: java.net.ConnectException: failed to connect to api.keen.io/108.168.254.131 (port 443) after 30000ms: connect failed: ENETUNREACH (Network is unreachable)
Location:
io.keen.client.java.KeenClient.handleFailure, line 1345
If you have any questions, please contact us at [email protected] or support.hockeyapp.net.
----==_mimepart_54f60ee2cde1_46fff2e0f4730e3--
I have 2 functions which create data that I want to send into my Keen Client.
public class CameraActivity extends Activity implements PictureCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
Map<String, Object> event = new HashMap<String, Object>();
@Override
public void onConnected(Bundle connectionHint) {
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
if (mLastLocation != null) {
mLatitude = String.valueOf(mLastLocation.getLatitude());
mLongitude = String.valueOf(mLastLocation.getLongitude());
event.put("Latitude",mLastLocation);
event.put("longitude",mLongitude);
KeenClient.client().queueEvent("android-sample-button-clicks", event);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
if (getIntent().getExtras() != null) {
bundle = getIntent().getExtras().getBundle("bundle");
if (bundle != null) {
int size = bundle.getInt("size", 0);
Log.d("MyLogs", "From Intent - " + bundle.getString("string"));
array = new String[size];
array = bundle.getStringArray("array");
String hashtag = array[1];
if (hashtag.indexOf("/") != -1) {
String[] parts = hashtag.split("/");
if (parts[1] != null) {
String part2 = parts[1]; //tracking_id
event.put("sticker_ID", part2);
event.put("device_ID",android_id);
}
}
}
}
@Override
protected void onPause() {
KeenClient.client().queueEvent("android-sample-button-clicks", event); //this doesn't look right to me.
KeenClient.client().sendQueuedEventsAsync();
if (mAdapter != null)
mAdapter.disableForegroundDispatch(this);
super.onPause();
}
}
You can see that I declare the event in the Activity itself, not in any of the functions. I need to add 4 data points to it. 2 come in onCreate, and the other 2 in onConnected. Hopefully sendQueuedEventsAsync will send whatever it has when onPause is called. This means that I need to queue the event whether or not onConnected has been called yet. Thus the queue event on line 13 is not sufficient. Thus I tried to add another one on line 42 so that it just queue whatever it has so far before it sends it, but somehow I don't feel like this is the correct way to do this. Its important that this is the same event. I don't want to send 2 separate events. How can I do this?
See comments in Issue #86
If you pass in a dictionary to addEvent
that doesn't have a timestamp, we'll set keen.timestamp
on that dictionary. That's normally fine, but if, for some reason, you re-use that dictionary for a later invocation of addEvent
, that timestamp will still be there, which is no good.
We'll either need to not mutate the dictionary (probably the right move), return the dictionary to its original form, or do something else.
At least one person has experienced an issue wherein certain devices' JSONObject implementation improperly serializes nested maps, producing:
{"keen":"{timestamp=...}", ...}
Instead of:
{"keen":{"timestamp":"..."}, ...}
The improper serialization results in JSON which the Keen API will not accept, returning a NamespaceTypeError. It's unknown how widespread this issue is, or why it's happening. However this may cause those devices to be unable to upload events using the Keen SDK.
Reports of additional devices experiencing this behavior would be greatly appreciated.
Parsing responses into the various types of QueryResult
is quite a bit of complex code at this point, and it's all nestled right in with the rest of KeenQueryClient
, which is becoming a bit unwieldy. Take a look at moving this out of KeenQueryClient
and figure out where this parsing responsibility should reside.
The README contains this snippet for working with the interval result:
for (Map.Entry<AbsoluteTimeframe, QueryResult> intervalResult : result.getIntervalResults().entrySet()) {
AbsoluteTimeframe timeframe = intervalResult.getKey();
long intervalCount = intervalResult.getValue().longValue();
// ... do something with the absolute timeframe and count result.
}
but that's wrong. The getIntervalResults
in the API has a different signature (List
not Map
):
public List<IntervalResultValue> getIntervalResults()
We removed the restriction on collections beginning with $ recently, and have updated our docs to reflect the change, but KeenClient-Java still restricts use of $ in KeenClient.java.
This restriction should be removed.
I have a use case for the KeenCallback where I would want to retry sending an event, persist the event for later, or log information that would help determine which event failed to publish.
Unfortunately, the current KeenCallback interface does not allow for Keen to pass the event data (project, collection, event properties, keen properties) to the callback so that further action can be taken (such as retrying, detailed logging, event storage, etc).
Adding these parameters to the callback methods or creating additional callback methods would constitute a breaking change to the interface as all existing implementations would need to be modified in order to compile with the new version of the interface.
My suggestion would be to create an additional callback interface, perhaps KeenEventCallback or something similar, that extends the KeenCallback interface with these new methods. Developers that need this type of callback could implement the advanced interface and pass it to the KeenClient during event publishing.
The KeenClient would need to be modified to check if the callback is an advanced callback and, if so, call the appropriate new callback method in place of or in addition to the original callback method.
If you think that other users of the Keen Java SDK would benefit from this feature, I would be happy to discuss further and put together a PR.
The class KeenClient
allows to add events asynchronously with the addEventAsync
methods. However, there is no way to know if the KeenClient is still processing tasks.
Could you add a method that awaits for task finalization, or a method to know if the task queue is empty?
When QueryResult.execute() returns a Map, its entries are not ordered. That's a problem when using the returned data to create a chart for example. Ideally, the method should return an ordered map. In the case of IntervalResults, I think this can be easily fixed by using a TreeMap instead of a HashMap here, and implementing a Comparator.
We have received a report that trying to use this SDK inside a Google App Engine app causes a crash. The error appeared to be a NoClassDefFoundError
while loading KeenLogging
. I suspect that the static initialization block is failing for some reason.
Hi, I'd like to have direct access to configuring proxy servers for the client to call through without environmental variables.
I'm willing to issue a pull request . I'd like to just run over the design I'm thinking of. Please point me in a different direction if you would like something else.
I was going to add a method: KeenConfig.setProxy(url). Internally this would create a java.net.Proxy instance for use with the HttpURLConnection in KeenHttpRequestRunnable.
I am more reluctant about the username and password. The only way I know of to set the authentication with HttpURLConnection is to set the default authenticator. This is a global variable. So I would rather not do that from code unless you moved to a library that supported it like (I think) Apache HttpClient. I personally don't need the authentication end, but I wanted to include it here for your thoughts.
Let's suppose we have KeenIO on our infrastructure up and running on my backend, and then I can access the Workbench, or extract the data for analysis, which it's quite good.
The thing is, we've noticed some outages on the Data Collection API during August (http://status.keen.io/#month), which are really really small (Availability of 99.960%), but we've lost some events on our way. So, we are thinking on different approaches to solve this issue: Does the SDK provide some kind of mechanism to retry? Or, should we write on our side? I've seen you have the method queueEvent, could we use the callback to detect if an error occurs, and then put it on the queue?
Please make READ_TIMEOUT and CONNECT_TIMEOUT configurable, so we can optimize the use of threads in our system.
thanks,
Would make it much easier if this library was published to the maven repo.
KeenQueryClient throws a NullPointerException if the result == null. The postRequest() method makes an assumption that all queries should return a result. But not all queries without a result are by default "unsuccessful" because it is possible to specify filters that don't generate any matches, so I believe the code block should have an additional check on the existence of error code & message and not throw a KeenQueryClientException unless errorCode and message != null.
// Get the result object.
Object result = responseMap.get(KeenQueryConstants.RESULT);
// for successful query, we should get a Result object. But just in case we don't...
if (result == null) {
String errorCode = responseMap.get(KeenQueryConstants.ERROR_CODE).toString();
// ^ this throws a NullPointerException, so perhaps we need if (responseMap.get(...) != null)
String message = responseMap.get(KeenQueryConstants.MESSAGE).toString();
String errorMessage = "Error response received from server";
if (errorCode != null) {errorMessage += " " + errorCode;}
if (message != null) {errorMessage += ": " + message;}
throw new KeenQueryClientException(errorMessage);
}
When we call onSuccess()
/onFailure
on KeenCallback
/KeenDetailedCallback
we swallow any exceptions. It probably makes sense to not generate exceptions unless debug mode is turned on, if those exceptions were raised in the SDK, but if the exception was raised in client code, an argument could be made that clients would want to see that exception and fix it.
We should talk a bit more about this and decide what to do here.
"You have the ability to overwrite the keen.timestamp property. This could be useful, for example, if you are backfilling historical data." – https://keen.io/docs/event-data-modeling/event-data-intro/
However,
https://github.com/keenlabs/KeenClient-Java/blob/master/src/main/java/io/keen/client/java/KeenClient.java#L239
currently prevents this.
I'm trying to use the library to import some legacy data and without being able to set this property, I can't do any useful time based analysis.
Thanks!
Cheers.
See comments in Issue #86
On the Do analysis with Keen IO section, it is not completed, it says: TODO. It should be fixed asap :(
I know I can write unit tests with some proper mocking framework (such as Mockito), and mock your SDK, and in this way check if the events are being saved on Keen. But, it would be good also to have some API to retrieve data from a given collection, just in case I want to get data, and check if it was written correctly (I mean, some kind of integration tests).
I know that I can use the REST API to do a query, but I have to build everything by hand, it would be nice to have it on the SDK instead. Just an idea.
Creating deeply nested maps in Java is kind of painful (see https://news.ycombinator.com/item?id=8637447). We should provide a utility to make it easier. One possible way (which has been explicitly requested at least once or twice) would be a method like:
Map<String, Object> buildEventFromJson(String json)
There are probably other good solutions.
Hi,
I received a crash report that seems to indicate that the Calendar.getInstance()
call was unable to initialise. Have you encountered this problem before? Does Calendar.getInstance()
not work for every device? It looks like this device was a Huawei.
Thanks
java.lang.ExceptionInInitializerError
at io.keen.client.java.KeenClient$Builder.buildInstance(Unknown Source)
at io.keen.client.java.KeenClient$Builder.build(Unknown Source)
...
Caused by: java.lang.NullPointerException
at java.util.Calendar.getHwFirstDayOfWeek(Calendar.java:1608)
at java.util.Calendar.setFirstDayOfWeekEx(Calendar.java:1573)
at java.util.Calendar.<init>(Calendar.java:746)
at java.util.GregorianCalendar.<init>(GregorianCalendar.java:338)
at java.util.GregorianCalendar.<init>(GregorianCalendar.java:314)
at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:378)
at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:368)
at io.keen.client.java.KeenClient.<clinit>(Unknown Source)
... 18 more
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.