Pagination on Google Analytics using Java - java

I'm implementing a data extraction from Google Analytics using Java and I'm following this example: https://developers.google.com/analytics/devguides/reporting/core/v4/quickstart/service-java
I managed to extract the data I need but I can't figure out how to set the start-index using its client. Below you can see the changed I made to the default implementation. I can set the page size but I can't find out how to set the start-index.
public GetReportsResponse getReport(String dateStart, String dateEnd) throws IOException {
String[] metricsArr = {"ga:users", "ga:newUsers", "ga:sessions", "ga:totalEvents"};
String[] dimensionsArr = {"ga:eventLabel","ga:eventCategory","ga:eventAction", "ga:country", "ga:countryIsoCode", "ga:dateHourMinute"};
// Create the DateRange object.
DateRange dateRange = new DateRange();
dateRange.setStartDate(dateStart);
dateRange.setEndDate(dateEnd);
// Create the Metrics object.
ArrayList<Metric> metrics = new ArrayList<Metric>();
for(String item : metricsArr){
Metric m = new Metric().setExpression(item).setAlias(item.replace("ga:", ""));
metrics.add(m);
}
ArrayList<Dimension> dimensions = new ArrayList<Dimension>();
for(String item : dimensionsArr){
Dimension d = new Dimension().setName(item);
dimensions.add(d);
}
// Create the ReportRequest object.
ReportRequest request = new ReportRequest()
.setViewId(this.VIEW_ID)
.setDateRanges(Arrays.asList(dateRange))
.setMetrics(metrics)
.setDimensions(dimensions)
.setFiltersExpression("ga:eventCategory=#NOTICE,ga:eventCategory==Document,ga:eventCategory==Document reader")
.setPageSize(10000);
ArrayList<ReportRequest> requests = new ArrayList<ReportRequest>();
requests.add(request);
// Create the GetReportsRequest object.
GetReportsRequest getReport = new GetReportsRequest().setReportRequests(requests);
// Call the batchGet method.
GetReportsResponse response = service.reports().batchGet(getReport).execute();
// Return the response.
return response;
}
How can I achieve that so I can navigate through all pages and extract all items?

The Reporting API V4 uses page tokens. The reply from the reporting API will return the next page's token, see nextPageToken. Using that you can make the exact same call but updating the pageToken in the request with the nextpagetoken from the previous reply. Note that the first call you make the reporting API will not have a page token attached to the request and the last page will not have the nextpagetoken set.
I hope that helps.

Related

How do I use the Grafana client for java to upload dashboards with a time-series filled panel to Grafana?

I am currently comparing time-series. They are stored in InfluxDB. My task is to get two time-series from InfluxDB, compare them and upload a visualization to Grafana. The comparison result would be output to console and the two time-series would be uploaded to Grafana in a dashboard and they should be in the same panel. I am trying to use the grafana-api-java-client found here. My problem is that I can not figure out how to do this with the provided examples and Javadocs. There is not a lot of documentation and the examples don't work properly in my case. I hope that someone has worked with this client and can explain how to properly add two time-series to a panel in a dashboard and upload it.
I will provide what I am doing and then post the examples from the github page of the API.
First of all this is how I am getting my time series:
public List<Double> getTimeSeries(String streetName, String start, String stop) {
//gets the query result
QueryResult queryResult = influxDB.query(new Query(String.format("SELECT value FROM your_measurement WHERE street='%s' " +
"AND time >= '%s' AND time <= '%s'", streetName, start, stop)));
//Gets the values from the query result
List<List<Object>> values = queryResult.getResults().iterator().next().getSeries().iterator().next().getValues();
//Adds the values to a list
List<Double> timeSeries = new ArrayList<>();
for (List<Object> li : values) {
timeSeries.add(Double.valueOf(li.get(1).toString()));
}
return timeSeries;
}
I can convert this list to an array of doubles:
double[] timeSeriesArray = timeSeries.stream().mapToDouble(d -> d).toArray();
The following is the first example. It works properly up until the getDashboard() and deleteDashboard() methods, where I get the error that such a dashboard does not exist, even though it does. I don't know what causes this error. Every new dashboard ends up in the folder "General". The method createDashboard() creates, as expected, an empty dashboard in Grafana.
import com.appnexus.grafana.client.GrafanaClient;
//Setup the client
GrafanaConfiguration grafanaConfiguration =
new GrafanaConfiguration().host("your_grafana_host").apiKey("Bearer your_secret_key");
GrafanaClient grafanaClient = new GrafanaClient(grafanaConfiguration);
//Setup the dashboard
String DASHBOARD_NAME = "new_dashboard";
Dashboard dashboard = new Dashboard()
.title(DASHBOARD_NAME)
.version(0);
GrafanaDashboard grafanaDashboard = new GrafanaDashboard().dashboard(dashboard);
//Make API calls
grafanaClient.createDashboard(grafanaDashboard);
grafanaClient.getDashboard(DASHBOARD_NAME);
grafanaClient.deleteDashboard(DASHBOARD_NAME);
This is the second example. I assume that I have to modify it in order to solve my problem. I had to replace two things to get this example to work, which I will explain with code comments. When executing this code it creates a dashboard with an empty panel. I expected something to be shown on the panel but it is empty and there are no axes.
import com.appnexus.grafana.client.GrafanaClient;
//Setup the client
GrafanaConfiguration grafanaConfiguration =
new GrafanaConfiguration().host("your_grafana_host").apiKey("Bearer your_secret_key");
GrafanaClient grafanaClient = new GrafanaClient(grafanaConfiguration);
//Setup the dashboard
String DASHBOARD_NAME = "new_dashboard";
DashboardPanelTarget dashboardPanelTarget =
new DashboardPanelTarget().refId("getSomeMetric").target("*");
DashboardPanelXAxis dashboardPanelXAxis =
new DashboardPanelXAxis().show(true).mode(DashboardPanelXAxis.Mode.TIME);
DashboardPanelYAxis dashboardPanelYAxis =
new DashboardPanelYAxis().format(DashboardPanelYAxis.Format.SHORT).logBase(1).show(true);
//Datasource is required or alerts cannot be added
DashboardPanel dashboardPanel =
new DashboardPanel()
//This might be where my data has to go but I am not sure.
.targets(new ArrayList<>(Collections.singletonList(dashboardPanelTarget)))
//Had to change DASHBOARD_DATA_SOURCE to a String -> "DASHBOARD_DATA_SOURCE", I assume it's just the name of the datasource.
//.datasource(DASHBOARD_DATA_SOURCE)
.datasource("DASHBOARD_DATA_SOURCE")
.type(DashboardPanel.Type.GRAPH)
.fill(1)
.title(dashboardName)
.linewidth(1)
.lines(true)
.height("300px")
.span(12)
.xaxis(dashboardPanelXAxis)
.yaxes(new ArrayList<>(Arrays.asList(dashboardPanelYAxis, dashboardPanelYAxis)));
DashboardRow dashboardRow =
new DashboardRow()
.collapse(false)
.panels(new ArrayList<>(Collections.singletonList(dashboardPanel)));
Dashboard dashboard =
new Dashboard()
.title(dashboardName)
.schemaVersion(1)
.rows(new ArrayList<>(Collections.singletonList(dashboardRow)));
DashboardMeta dashboardMeta = new DashboardMeta().canSave(true).slug(dashboardName);
GrafanaDashboard grafanaDashboard =
new GrafanaDashboard().meta(dashboardMeta).dashboard(dashboard);
//create new dashboard
//Had to change createDashboardTest() to createDashboard(), because createDashboardTest() doesn't seem to exist
//DashboardMeta createdDashboardMeta = createDashboardTest(grafanaDashboard);
DashboardMeta createdDashboardMeta = createDashboard(grafanaDashboard);

How to parse protobuf data of Envelope.Payload.Data?

I’m using Hyperledger Fabric Java SDK to get a transaction by txId. The return object includes Transaction Information.
TransactionInfo txInfo = channel.queryTransactionByID(txId);
Common.Envelope envelope = txInfo.getEnvelope();
Common.Payload payload = Common.Payload.parseFrom(envelope.getPayload());
The Payload message includes headers and data. I can parse headers by using Common.Header.ChannelHeader and Common.Header.SignatureHeader.
Common.ChannelHeader channelHeader = Common.ChannelHeader.parseFrom(payload.getHeader().getChannelHeader());
Common.SignatureHeader signatureHeader = Common.SignatureHeader.parseFrom(payload.getHeader().getSignatureHeader());
The problem is, I cannot see any message type to get data from Payload.
My expectation would be like,
SomeMessage someMsg = SomeMessage.parseFrom(payload.getData());
What is the ideal approach to get a data object?
Thanks to Driden Myung's tip, Finally found a way to parse QSCC responses into TxReadWriteSet or even KVRWSet !!
Here is an example:
TransactionInfo txInfo = channel.queryTransactionByID(txId);
Common.Envelope envelope = txInfo.getEnvelope();
Common.Payload payload = Common.Payload.parseFrom(envelope.getPayload());
FabricTransaction.Transaction transaction = FabricTransaction.Transaction.parseFrom(payload.getData());
FabricTransaction.TransactionAction action = transaction.getActionsList().get(0); // 0 is a index
FabricTransaction.ChaincodeActionPayload chaincodeActionPayload = FabricTransaction.ChaincodeActionPayload.parseFrom(action.getPayload());
FabricProposalResponse.ProposalResponsePayload prp = FabricProposalResponse.ProposalResponsePayload.parseFrom(chaincodeActionPayload.getAction().getProposalResponsePayload());
FabricProposal.ChaincodeAction ca = FabricProposal.ChaincodeAction.parseFrom(prp.getExtension());
Rwset.TxReadWriteSet txrws = Rwset.TxReadWriteSet.parseFrom(ca.getResults());
TxReadWriteSetInfo txrwsInfo = new TxReadWriteSetInfo(txrws);
KvRwset.KVRWSet kvrwSet = txrwsInfo.getNsRwsetInfo(0).getRwset();
KvRwset.KVWrite kvWrite = kvrwSet.getWrites(0);
String writeVal = kvWrite.getValue().toStringUtf8();
I found the answer.
FabricTransaction.Transaction transaction = FabricTransaction.Transaction.parseFrom(payload.getData());
After that,
FabricTransaction.TransactionAction action = transaction.getActionsList().get(index);
FabricTransaction.ChaincodeActionPayload chaincodeActionPayload = FabricTransaction.ChaincodeActionPayload.parseFrom(action.getPayload());
chaincodeActionPayload.getAction().getEndorsementsList().forEach(endorsement -> {
// This is my current point
???? endorser = ????.parseFrom(endorsement.getEndorser());
});
Let me add if I can find more. Anybody add comments welcome.
We have faced a similar problem to get the request data from a transaction.
The following code will help to get the transaction request data of a transaction
Fabric SDK version : 2.1.4
// get transaction from transaction ID
TransactionInfo txInfo = channel.queryTransactionByID(txId);
// transaction is stored inside the envelope containing the payload and signature
Common.Envelope envelope = txInfo.getEnvelope();
// parse payload from the envelope
Common.Payload payload = Common.Payload.parseFrom(envelope.getPayload());
// payload contains Header and Data. We are parsing data to get the transaction
TransactionPackage.Transaction transaction = TransactionPackage.Transaction.parseFrom(payload.getData());
// get first action from the transaction action list. it contains input and other details
TransactionPackage.TransactionAction action = transaction.getActionsList().get(0); // 0 is a index
// chaincode action payload contains input parameters. So we are taking the action payload
TransactionPackage.ChaincodeActionPayload chaincodeActionPayload = TransactionPackage.ChaincodeActionPayload.parseFrom(action.getPayload());
// chaincode ProposalPayload contains Input and TransientMap. We are parsing actionPayload to proposalPayload
ProposalPackage.ChaincodeProposalPayload prp = ProposalPackage.ChaincodeProposalPayload.parseFrom(chaincodeActionPayload.getChaincodeProposalPayload());
// parse the input to chaincodeInvocationSpec so that we can unmarshal the input
Chaincode.ChaincodeInvocationSpec chaincodeInvocationSpec = Chaincode.ChaincodeInvocationSpec.parseFrom(prp.getInput());
// get the input and parse the arg list and get input arguments
chaincodeInvocationSpec.getChaincodeSpec().getInput().getArgsList().get(ChaincodeInput.ARGS_FIELD_NUMBER).toStringUtf8();

AWS SSM parameter store not fetching all key/values

Could someone let me know why the below code only fetching few entries from the parameter store ?
GetParametersByPathRequest getParametersByPathRequest = new GetParametersByPathRequest();
getParametersByPathRequest.withPath("/").setRecursive(true);
getParametersByPathRequest.setWithDecryption(true);
GetParametersByPathResult result = client.getParametersByPath(getParametersByPathRequest);
result.getParameters().forEach(parameter -> {
System.out.println(parameter.getName() + " - > " + parameter.getValue());
});
GetParametersByPath is a paged operation. After each call you must retrieve NextToken from the result object, and if it's not null and not empty you must make another call with it added to the request.
Here's an example using DescribeParameters, which has the same behavior:
DescribeParametersRequest request = new DescribeParametersRequest();
DescribeParametersResult response;
do
{
response = client.describeParameters(request);
for (ParameterMetadata param : response.getParameters())
{
// do something with metadata
}
request.setNextToken(response.getNextToken());
}
while ((response.getNextToken() != null) && ! respose.getNextToken.isEmpty());
Here is the code, based on the code above, for the new 2.0 version of AWS SSM manager. Notice I have set the maxResults to 1 to prove out the loop. You will want to remove that. AWS has mentioned that in the new code they wanted to emphasize immutability.
Using this dependency:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>ssm</artifactId>
<version>2.10.32</version>
</dependency>
I came up with this code:
private void refreshCache() {
StopWatch sw = StopWatch.createStarted();
GetParametersByPathRequest request = GetParametersByPathRequest.builder()
.path(prefix)
.withDecryption(useDecryption)
.maxResults(1)
.build();
GetParametersByPathResponse response;
do {
response = ssm.getParametersByPath(request);
for (Parameter p : response.parameters()) {
//do something with the values.
}
request = GetParametersByPathRequest.builder()
.path(prefix)
.withDecryption(useDecryption)
.nextToken(response.nextToken())
.maxResults(1)
.build();
}
while (StringUtils.isNotBlank(response.nextToken()));
LOG.trace("Refreshed parameters in {}ms", sw.getTime());
}
private void getSsmParams() {
AWSSimpleSystemsManagement client = AWSSimpleSystemsManagementClientBuilder.defaultClient();
GetParametersByPathRequest request = new GetParametersByPathRequest();
request.withRecursive(true);
request.withPath('/your/path/parameterName').setWithDecryption(true);
GetParametersByPathResult response;
do {
response = client.getParametersByPath(request);
for (Parameter p : response.parameters()) {
//do something with the values. maybe add to a list
}
request.setNextToken(response.getNextToken())
}
while (StringUtils.isNotBlank(response.getNextToken()));
}
Above piece of code worked for me .ssm only sends 10 parameters at a time, so if you want to fetch more than 10 parameters from ssm parameter store programatically you will have to use multiple calls to fetch them. here the token is important , if there are more values in the path (request.withPath('/your/path/parameterName')) you have given, it will send a token indicating that there are more values in the given path ,and you will have to make the following request with the token received from the previous request in order to get the rest of the values.

How to get Facebook Rate Limit Header using Facebook4J?

According to Facebook Docs
If your app is making enough calls to be considered for rate limiting by our system, we return an X-App-Usage HTTP header. [...] When any of these metrics exceed 100 the app will be rate limited.
I am using Facebook4J to connect my application to the Facebook API. But I could not find any documentation about how I can get the X-App-Usage HTTP header after a Facebook call, in order to avoid being rate limited. I want to use this header to know dinamically if I need to increase or decrease the time between each API call.
So, my question is: using Facebook4J, is possible to check if Facebook returned the X-App-Usage HTTP header and get it? How?
There is a getResponseHeader method for the response of BatchRequests in facebook4j see Facebook4j code examples
You could try getResponseHeader("X-App-Usage")
// Executing "me" and "me/friends?limit=50" endpoints
BatchRequests<BatchRequest> batch = new BatchRequests<BatchRequest>();
batch.add(new BatchRequest(RequestMethod.GET, "me"));
batch.add(new BatchRequest(RequestMethod.GET, "me/friends?limit=50"));
List<BatchResponse> results = facebook.executeBatch(batch);
BatchResponse result1 = results.get(0);
BatchResponse result2 = results.get(1);
// You can get http status code or headers
int statusCode1 = result1.getStatusCode();
String contentType = result1.getResponseHeader("Content-Type");
// You can get body content via as****() method
String jsonString = result1.asString();
JSONObject jsonObject = result1.asJSONObject();
ResponseList<JSONObject> responseList = result2.asResponseList();
// You can map json to java object using DataObjectFactory#create****()
User user = DataObjectFactory.createUser(jsonString);
Friend friend1 = DataObjectFactory.createFriend(responseList.get(0).toString());
Friend friend2 = DataObjectFactory.createFriend(responseList.get(1).toString());

Is it possible using the Java AWS API to update a Route53 record?

I have a hosted domain on AWS Route53. Under that domain I have an 'A' record for a subdomain.
I would like to be able to update the IP address of the 'A' record using the Java API. However, when looking at the setAction method of the com.amazonaws.services.route53.model.Change class, it only accepts the CREATE or DELETE values. This seems to match the allowed values in the XML message that the Java API sends behind the scenes.
Is there any way to just update the IP address, or do I have to delete the original record and then create it again?
Thanks
It worked for me using this piece of code:
ResourceRecord record = new ResourceRecord(loadBalancer);
List<ResourceRecord> records = new ArrayList<ResourceRecord>();
records.add(record);
ResourceRecordSet recordsSet = new ResourceRecordSet();
recordsSet.setResourceRecords(records);
recordsSet.setType(RRType.CNAME);
recordsSet.setTTL(900L);
recordsSet.setName(subdomain + ".");
Change change = new Change(ChangeAction.CREATE, recordsSet);
List<Change> changes = new ArrayList<Change>();
changes.add(change);
ChangeBatch batch = new ChangeBatch(changes);
ChangeResourceRecordSetsRequest request = new ChangeResourceRecordSetsRequest();
request.setChangeBatch(batch);
request.setHostedZoneId(hostedZoneId);
ChangeResourceRecordSetsResult result = getRoute53Client().changeResourceRecordSets(request);
System.out.println(result);
Just replace the variables I used with proper data. (subdomain, loadBalancer and hostedZoneId). The method getRoute53Client() returns an instance of the AmazonRoute53Client class from the AWS API.
ResourceRecord rr = new ResourceRecord(IPAdress); // IPAddress will be String variable that has IP value
List<ResourceRecord> rrList = new ArrayList<ResourceRecord>();
rrList.add(rr);
// Create a ResourceRecordSet
ResourceRecordSet resourceRecordSet = new ResourceRecordSet();
resourceRecordSet.setName(domainName); //domainName is String value of your domain
resourceRecordSet.setType(RRType.A); //type of ResourceRecordSet
resourceRecordSet.setTTL(new Long(300));
resourceRecordSet.setWeight(new Long(0));
resourceRecordSet.setResourceRecords(rrList);
// Create a change
Change change = new Change(ChangeAction.CREATE, resourceRecordSet);
List<Change> changesList = new ArrayList<Change>();
changesList.add(change);
// Create a change batch
ChangeBatch changeBatch = new ChangeBatch(changesList);
// Create ChangeResourceRecordSetRequest.
ChangeResourceRecordSetsRequest request = new ChangeResourceRecordSetsRequest(hostedZoneID, changeBatch); //hostedZoneId is variable that is the id of HostedZone
// Send the request and get the response.
ChangeResourceRecordSetsResult result = amazonRoute53Client.changeResourceRecordSets(request);
// Print the result
System.out.println(result.getChangeInfo());
The only way is to use DELETE / CREATE sequence as mentioned here.
Creating a Change Batch Request
To create a change batch request, use the ChangeResourceRecordSets
action ChangeBatch element. You use CREATE and DELETE actions within
the ChangeBatch element for each record that you want to update. If
you are only creating records, then you will only use CREATE actions.
hostedzoneId = "hosted zone id from the route53"
aliasTargetHostedzoneId = "zone id of the connected resource such as loadbalancer, cloudfront etc.."
Route53Client route53Client = Route53Client.builder()
.credentialsProvider(StaticCredentialsProvider.create(awsCreds))
.region(Region.AWS_GLOBAL)
.build();
AliasTarget aliasTarget = AliasTarget.builder()
.dnsName(loadBalancerDomain)
.evaluateTargetHealth(false)
.hostedZoneId(aliasTargetHostedzoneId)
.build();
// Create a ResourceRecordSet
ResourceRecordSet resourceRecordSet = ResourceRecordSet.builder()
.name(fullDomainName+".")
.type(RRType.A)
.aliasTarget(aliasTarget)
.build();
// Create a change
Change change = Change.builder()
.action(ChangeAction.CREATE)
.resourceRecordSet(resourceRecordSet)
.build();
List<Change> changesList = new ArrayList<Change>();
changesList.add(change);
// Create a change batch
ChangeBatch changeBatch = ChangeBatch.builder()
.changes(changesList)
.build();
// Create ChangeResourceRecordSetRequest.
ChangeResourceRecordSetsRequest request = ChangeResourceRecordSetsRequest.builder()
.hostedZoneId(hostedzoneId)
.changeBatch(changeBatch)
.build();
// Send the request and get the response.
ChangeResourceRecordSetsResponse result = route53Client.changeResourceRecordSets(request);

Categories

Resources