Giter VIP home page Giter VIP logo

keenclient-java's People

Contributors

baumatron avatar claireyoung avatar dkador avatar elof avatar filipshark avatar geeber avatar gorzell avatar jstanier avatar karlvr avatar louiszuckerman avatar maciej-nedza avatar masojus avatar mikereinhold avatar piotrek-buchman avatar rebeccastandig avatar smurthas avatar wetzler avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

keenclient-java's Issues

Support Java 6

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.

Global properties overrides keenProperties when global has keen key

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!

Thread pool prevents Tomcat from shutting down

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 :-)

addEventAsync() issue under load

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 ?

Add support for Cached Queries

MVP

  • Create Saved Query
  • Cache a Saved Query
  • Uncache a Saved Query
  • Delete a Saved Query
  • Retrieve Results from Saved Query

Stretch

  • Retrieve definition of a saved query
  • Update a cached query

App crash if hostname blocked in host file

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)

Missing transitive dependencies on Android artifact

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.

Cannot instanciate JacksonJsonHandler

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.

Scoped Key update needed for Java SDK

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.

Deal with __fake_root

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.

Keen.location.coordinates becomes invalid on Samsung Galaxy S3

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.

See screenshots attached (nexus5.png, samsungS3.png).
nexus5
samsungs3

NPE in KeenClient.getKeenCacheSubDirectories() when getKeenCacheDirectory() returns an invalid directory

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();
}

A null property_value isn't allowed in Filter

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.

Long contention Warning Android

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...

KeenQueryTestBase lower-level HTTP Request validation

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.

Emulator JSON file failure

Using version 2.0.3 I am able to get the SDK "stuck" on an empty event file by doing the following:

  1. Uninstall the sample app
  2. Run the sample app
  3. Click "Send Event!" (wait a few seconds to theoretically let the FS flush)
  4. Quit the emulator without pausing the app
  5. Run the app
  6. Pause the app by hitting the home button

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.

Option to disable the KeenClient's log handler

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.

unable to send events with Java sdk (error is: "The specified JSON is invalid. No JSON object could be decoded")

(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);
}

}

Performance degradation when queueing events using queueEvents(…)

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

Must specify a non-null, non-empty event

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

New Crash Group for huedoku 1.1 (5)

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

<style> html { -webkit-text-size-adjust: none; } body, html { background-color: #fff; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; margin: 0px; padding: 0px; width: 100%; } h2 { font-size: 120%; } h3 { background: #dce0e3; border-top: 1px solid #fff; margin: 0px; padding: 10px 15px; font-size: 100%; } ul { margin-left: 20px; padding-left: 0px; } div.well-container { margin: 0px; padding: 0px; } div.well { padding: 0px; } div.below-well { border-top: 1px solid #dce0e3; color: #000; padding: 10px 0px; text-align: center; } div.below-well a { color: #3f4e57 !important; text-decoration: underline; } div.message-header { background: #fff; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(255, 255, 255, 0.0)), to(rgba(248, 249, 251, 1.0))); background-image: -moz-linear-gradient(center top, rgba(255, 255, 255, 0) 0%, rgba(248, 249, 251, 1.0) 100%); border-bottom: 1px solid #dce0e3; padding: 10px 15px; } div.message-header img { border-radius: 4px; -webkit-border-radius: 4px; -moz-border-radius: 4px; float: right; height: 36px; width: 36px; } div.message-body, div.message-help { padding: 10px 15px; } div.message-help { border-top: 1px solid #dce0e3; } div.message-help li { margin-bottom: 15px; } div.small_icon, div.small_icon_no_border { display: block; float: none; margin: 4px 0px 0px 0px; padding: 0px; text-align: center; width: 36px; } div.small_icon span.highlight { background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(255, 255, 255, 0.699219)), to(rgba(255, 255, 255, 0.199219))); background-image: -moz-linear-gradient(center top, rgba(255, 255, 255, 0.699219) 0%, rgba(255, 255, 255, 0.199219) 100%); border-bottom-left-radius: 20px 6px; border-bottom-right-radius: 25px 6px; border-top-left-radius: 9px 9px; border-top-right-radius: 9px 9px; display: block; height: 18px; margin: -1px 0px; position: absolute; width: 36px; z-index: 5; } div.small_icon img, div.small_icon_no_border img { color: #888; width: 36px; height: 36px; } div.small_icon img { -webkit-box-shadow: 0px 2px 4px rgba(0,0,0,0.5); -moz-box-shadow: 0px 2px 4px rgba(0,0,0,0.5); box-shadow: 0px 2px 4px rgba(0,0,0,0.5); border-radius: 6px; } .btn { background-color: #f5f5f5; background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); background-image: linear-gradient(top, #ffffff, #e6e6e6); background-repeat: repeat-x; border: 1px solid #cccccc; border-bottom-color: #b3b3b3; border-color: #e6e6e6 #e6e6e6 #bfbfbf; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); border-radius: 4px; -webkit-border-radius: 4px; -moz-border-radius: 4px; box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); color: #fff; color: #333333; cursor: pointer; display: inline-block; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); font-size: 13px; padding: 4px 10px 4px; line-height: 18px; margin-bottom: 0; text-align: center; text-decoration: none; text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); vertical-align: middle; } .btn-ha-primary { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #389be8; background-image: -moz-linear-gradient(top, #4aa4ea, #1c8de5); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#4aa4ea), to(#1c8de5)); background-image: -webkit-linear-gradient(top, #4aa4ea, #1c8de5); background-image: -o-linear-gradient(top, #4aa4ea, #1c8de5); background-image: linear-gradient(to bottom, #4aa4ea, #1c8de5); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff4aa4ea', endColorstr='#ff1c8de5', GradientType=0); border-color: #1c8de5 #1c8de5 #1363a2; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); *background-color: #1c8de5; filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); } .btn-ha-primary:hover, .btn-ha-primary:focus, .btn-ha-primary:active, .btn-ha-primary.active, .btn-ha-primary.disabled, .btn-ha-primary[disabled] { color: #ffffff; background-color: #1c8de5; *background-color: #187fcf; } .btn-ha-primary:active, .btn-ha-primary.active { background-color: #1571b9 ; } div.message-help li .btn { margin-top: 5px; } div.overflow { overflow: scroll; max-width: 100%; } @media only screen and (min-device-width:768px) { body, html { background-color: #f3f6f8; } div.well-container { margin: 0px; padding: 20px; } div.well { background-color: #fff; border-radius: 4px; -webkit-border-radius: 4px; -moz-border-radius: 4px; box-shadow: 0 2px 2px rgba(0, 0, 0, 0.5); -moz-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.5); -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.5); } div.below-well { border-top: none; padding: 20px 10px 10px; text-align: right; } } .progress { overflow: hidden; height: 18px; margin-bottom: 0px; background-color: #f7f7f7; background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: linear-gradient(top, #f5f5f5, #f9f9f9); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .progress .bar { width: 0%; height: 18px; line-height: 18px; color: #ffffff; font-size: 12px; text-align: left; padding: 0px 5px; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #0e90d2; background-image: -moz-linear-gradient(top, #149bdf, #0480be); background-image: -ms-linear-gradient(top, #149bdf, #0480be); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); background-image: -webkit-linear-gradient(top, #149bdf, #0480be); background-image: -o-linear-gradient(top, #149bdf, #0480be); background-image: linear-gradient(top, #149bdf, #0480be); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; -webkit-transition: width 0.6s ease; -moz-transition: width 0.6s ease; -ms-transition: width 0.6s ease; -o-transition: width 0.6s ease; transition: width 0.6s ease; float: left; } .sec-label { height: 18px; line-height: 18px; float: left; margin-left: 5px; font-size: 12px; color: #0088cc; } table a { text-decoration: none; color: #0088cc; } table a:hover { text-decoration: none; color: #005580; } td.app-title { white-space: nowrap; } table.table-bordered { border-left: none; border-right: none; border-top: none; border-bottom: none; border-radius: 0px; } table.table-bordered th, table.table-bordered td { border-left: none; border-right: none; border-radius: 0px !important; } table.table-bordered th { border-color: transparent; border-width: 0px 0px 0px 1px; -webkit-border-image: -webkit-gradient(linear, 0 100%, 0 20%, from(#dedede), to(rgba(222, 222, 222, 0))) 1 100%; } table.table-bordered th:first-of-type, table.table-bordered th.actions { border-left: none; border-width: 0px; } table.table-bordered th.icon + th.title { border: none; } table.table-bordered col.new-actions { width: 30px; } table.table-bordered th.new-actions, table.table-bordered td.new-actions { text-align: center; } table.table-bordered th.new-actions .btn-group, table.table-bordered td.new-actions .btn-group { float: none; } table.table-bordered th.new-actions .btn-group > .dropdown-toggle, table.table-bordered td.new-actions .btn-group > .dropdown-toggle { box-shadow: none; -moz-box-shadow: none; -webkit-box-shadow: none; opacity: 0.2; padding: 0px; } table.table-bordered th.new-actions .btn-group > .dropdown-toggle:hover, table.table-bordered td.new-actions .btn-group > .dropdown-toggle:hover { opacity: 1.0; } table.table-bordered th.new-actions ul, table.table-bordered td.new-actions ul { min-width: 80px !important; } table.table-bordered th.new-actions ul li, table.table-bordered td.new-actions ul li { text-align: left; } table tr > td:first-child { padding-right:10px } div.below-headline table { border-top: 1px solid #eee; } div#infinite { padding-bottom: 20px; } </style>

huedoku 1.1 (5)

Platform: Android
Release Type: Beta

Db495b655fd2bbf4c2ed1e0ce4f821e7

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

View on HockeyApp

If you have any questions, please contact us at [email protected] or support.hockeyapp.net.

----==_mimepart_54f60ee2cde1_46fff2e0f4730e3--

Inserting data to 1 event in 2 separate functions (which are called at different times)?

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?

Keen.addEvent mutates the passed dictionary

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.

Android built-in JSON library may not reliably serialize nested maps

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.

Move result parsing out of KeenQueryClient

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.

README mismatch with API

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()

KeenCallback with event map parameters

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.

KeenClient graceful shutdown

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?

QueryResult.execute() doesn't return ordered values

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.

SDK crashes in Google App Engine

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.

Add Support For Proxy Servers

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.

Some questions about queueEvent and sendQueuedEvents

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?

Add to maven repo

Would make it much easier if this library was published to the maven repo.

KeenQueryClient NullPointerException

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);
  }

Swallowing exceptions in client callbacks

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.

Can't set keen.timestamp property

"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.

Can't get data from a given Collection using the SDK

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.

NullPointerException - Calendar.getInstance()

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.