QPS, latencies recorded with authentication
diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc
index e116175..b422988 100644
--- a/test/cpp/qps/report.cc
+++ b/test/cpp/qps/report.cc
@@ -35,6 +35,7 @@
#include <grpc/support/log.h>
#include "test/cpp/qps/stats.h"
+#include "user_data_client.h"
namespace grpc {
namespace testing {
@@ -120,5 +121,107 @@
[](ResourceUsage u) { return u.wall_time; }));
}
+UserDataClient userDataClient(grpc::CreateChannel("localhost:50052", grpc::InsecureCredentials(),
+ ChannelArguments()));
+
+//Leaderboard Reported implementation.
+void UserDatabaseReporter::ReportQPS(const ScenarioResult& result) const {
+ double qps = result.latencies.Count() /
+ average(result.client_resources,
+ [](ResourceUsage u) { return u.wall_time; });
+
+ userDataClient.setAccessToken(access_token_);
+ userDataClient.setQPS(qps);
+
+ int userDataState = userDataClient.sendDataIfReady();
+
+ switch(userDataState) {
+ case 1:
+ gpr_log(GPR_INFO, "Data sent to user database successfully");
+ break;
+ case -1:
+ gpr_log(GPR_INFO, "Data could not be sent to user database");
+ break;
+ }
+}
+
+void UserDatabaseReporter::ReportQPSPerCore(const ScenarioResult& result,
+ const ServerConfig& server_config) const {
+ double qps = result.latencies.Count() /
+ average(result.client_resources,
+ [](ResourceUsage u) { return u.wall_time; });
+
+ double qpsPerCore = qps / server_config.threads();
+
+ userDataClient.setAccessToken(access_token_);
+ //TBD
+ userDataClient.setQPSPerCore(qpsPerCore);
+
+ int userDataState = userDataClient.sendDataIfReady();
+
+ switch(userDataState) {
+ case 1:
+ gpr_log(GPR_INFO, "Data sent to user database successfully");
+ break;
+ case -1:
+ gpr_log(GPR_INFO, "Data could not be sent to user database");
+ break;
+ }
+}
+
+void UserDatabaseReporter::ReportLatency(const ScenarioResult& result) const {
+ userDataClient.setAccessToken(access_token_);
+ userDataClient.setLatencies(result.latencies.Percentile(50) / 1000,
+ result.latencies.Percentile(90) / 1000,
+ result.latencies.Percentile(95) / 1000,
+ result.latencies.Percentile(99) / 1000,
+ result.latencies.Percentile(99.9) / 1000);
+
+ int userDataState = userDataClient.sendDataIfReady();
+
+ switch(userDataState) {
+ case 1:
+ gpr_log(GPR_INFO, "Data sent to user database successfully");
+ break;
+ case -1:
+ gpr_log(GPR_INFO, "Data could not be sent to user database");
+ break;
+ }
+}
+
+void UserDatabaseReporter::ReportTimes(const ScenarioResult& result) const {
+ double serverSystemTime = 100.0 * sum(result.server_resources,
+ [](ResourceUsage u) { return u.system_time; }) /
+ sum(result.server_resources,
+ [](ResourceUsage u) { return u.wall_time; });
+ double serverUserTime = 100.0 * sum(result.server_resources,
+ [](ResourceUsage u) { return u.user_time; }) /
+ sum(result.server_resources,
+ [](ResourceUsage u) { return u.wall_time; });
+ double clientSystemTime = 100.0 * sum(result.client_resources,
+ [](ResourceUsage u) { return u.system_time; }) /
+ sum(result.client_resources,
+ [](ResourceUsage u) { return u.wall_time; });
+ double clientUserTime = 100.0 * sum(result.client_resources,
+ [](ResourceUsage u) { return u.user_time; }) /
+ sum(result.client_resources,
+ [](ResourceUsage u) { return u.wall_time; });
+
+ userDataClient.setAccessToken(access_token_);
+ userDataClient.setTimes(serverSystemTime, serverUserTime,
+ clientSystemTime, clientUserTime);
+
+ int userDataState = userDataClient.sendDataIfReady();
+
+ switch(userDataState) {
+ case 1:
+ gpr_log(GPR_INFO, "Data sent to user database successfully");
+ break;
+ case -1:
+ gpr_log(GPR_INFO, "Data could not be sent to user database");
+ break;
+ }
+}
+
} // namespace testing
} // namespace grpc
diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h
index 630275e..2e5b627 100644
--- a/test/cpp/qps/report.h
+++ b/test/cpp/qps/report.h
@@ -106,6 +106,20 @@
void ReportTimes(const ScenarioResult& result) const GRPC_OVERRIDE;
};
+/** Reporter for client leaderboard. */
+class UserDatabaseReporter : public Reporter {
+ public:
+ UserDatabaseReporter(const string& name, const string& access_token) : Reporter(name), access_token_(access_token) {}
+
+ private:
+ std::string access_token_;
+ void ReportQPS(const ScenarioResult& result) const GRPC_OVERRIDE;
+ void ReportQPSPerCore(const ScenarioResult& result,
+ const ServerConfig& config) const GRPC_OVERRIDE;
+ void ReportLatency(const ScenarioResult& result) const GRPC_OVERRIDE;
+ void ReportTimes(const ScenarioResult& result) const GRPC_OVERRIDE;
+};
+
} // namespace testing
} // namespace grpc
diff --git a/test/cpp/qps/run_authenticated_test.sh b/test/cpp/qps/run_authenticated_test.sh
new file mode 100755
index 0000000..3cde649
--- /dev/null
+++ b/test/cpp/qps/run_authenticated_test.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+
+CLIENT_ID='1018396037782-tv81fshn76nemr24uuhuginceb9hni2m.apps.googleusercontent.com'
+CLIENT_SECRET='_HGHXg4DAA59r4w4x8p6ARzD'
+GRANT_TYPE='http://oauth.net/grant_type/device/1.0'
+ACCESS_TOKENS_DIR='/tmp/auth_lead_access_tokens'
+AUTH_TOKEN_LINK='https://www.googleapis.com/oauth2/v3/token'
+GOOGLE_ACCOUNTS_LINK='https://accounts.google.com/o/oauth2/device/code'
+USER_INFO_LINK='https://www.googleapis.com/oauth2/v1/userinfo'
+#Performs first time authentication
+#Or re-authentication if refresh token expires
+RE_AUTHENTICATE() {
+ INIT_AUTH_JSON=$(curl -s -d "client_id=$CLIENT_ID&scope=email profile" $GOOGLE_ACCOUNTS_LINK)
+
+ USER_CODE=$(echo $INIT_AUTH_JSON | jq .user_code | sed -e 's/^"//' -e 's/"$//')
+ echo 'Please use the following user code in the browser:' $USER_CODE
+ echo
+
+ VERIFICATION_URL=$(echo $INIT_AUTH_JSON | jq '.verification_url' | sed -e 's/^"//' -e 's/"$//')
+ echo 'Verification URL:' $VERIFICATION_URL
+ echo
+
+ xdg-open $VERIFICATION_URL
+
+ DEVICE_CODE=$(echo $INIT_AUTH_JSON | jq '.device_code' | sed -e 's/^"//' -e 's/"$//')
+ INTERVAL=$(echo $INIT_AUTH_JSON | jq '.interval' | sed -e 's/^"//' -e 's/"$//')
+
+ AUTH_JSON=$(curl -s -d "client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&code=$DEVICE_CODE&grant_type=$GRANT_TYPE" $AUTH_TOKEN_LINK)
+ ACCESS_TOKEN=$(echo $AUTH_JSON | jq '.access_token' | sed -e 's/^"//' -e 's/"$//')
+
+ while [ $ACCESS_TOKEN == 'null' ]
+ do
+ sleep $INTERVAL
+ AUTH_JSON=$(curl -s -d "client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&code=$DEVICE_CODE&grant_type=$GRANT_TYPE" $AUTH_TOKEN_LINK)
+ ACCESS_TOKEN=$(echo $AUTH_JSON | jq '.access_token' | sed -e 's/^"//' -e 's/"$//')
+ done
+
+ USER_DETAILS=$(curl -s $USER_INFO_LINK?access_token=$ACCESS_TOKEN)
+ USER_ID=$(echo $USER_DETAILS | jq '.email' | sed -e 's/^"//' -e 's/"$//' | awk -F"@" '{print $1}' | sed -e 's/\.//g' | awk '{print tolower($0)}')
+ echo $AUTH_JSON > $ACCESS_TOKENS_DIR/$USER_ID
+}
+
+#Use existing access token
+USE_ACCESS_TOKEN() {
+ ACCESS_TOKEN=$(jq '.access_token' $ACCESS_TOKENS_DIR/$USER_ID | sed -e 's/^"//' -e 's/"$//')
+
+ USER_DETAILS=$(curl -s $USER_INFO_LINK?access_token=$ACCESS_TOKEN)
+
+ ID=$(echo $USER_DETAILS | jq '.id' | sed -e 's/^"//' -e 's/"$//')
+
+ if [ $ID == 'null' ]; then
+ REFRESH_ACCESS_TOKEN
+ fi
+}
+
+#Obtain new access token using refresh token
+REFRESH_ACCESS_TOKEN() {
+ REFRESH_TOKEN=$(jq '.refresh_token' $ACCESS_TOKENS_DIR/$USER_ID | sed -e 's/^"//' -e 's/"$//')
+ if [ $REFRESH_TOKEN == 'null' ]; then
+ RE_AUTHENTICATE
+ else
+ REFRESH_JSON=$(curl -s -d "refresh_token=$REFRESH_TOKEN&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&grant_type=refresh_token" $AUTH_TOKEN_LINK)
+
+ ACCESS_TOKEN=$(echo $REFRESH_JSON | jq '.access_token')
+ if [ $ACCESS_TOKEN == 'null' ]; then
+ RE_AUTHENTICATE
+ else
+ NEW_AUTH_JSON=$(jq ".access_token=$ACCESS_TOKEN" $ACCESS_TOKENS_DIR/$USER_ID)
+ echo $NEW_AUTH_JSON > $ACCESS_TOKENS_DIR/$USER_ID
+ fi
+ fi
+}
+
+#create directory to store tokens, if not already present
+[ ! -d $ACCESS_TOKENS_DIR ] && mkdir $ACCESS_TOKENS_DIR
+
+#Convert user entered email id to unique string by converting to splitting on '@' symbol, if present,
+#removing '.'s and converting to lowercase
+USER_ID=$(echo $2 | awk -F"@" '{print $1}' | sed -e 's/\.//g' | awk '{print tolower($0)}')
+
+if [ -s $ACCESS_TOKENS_DIR/$USER_ID ]; then
+ USE_ACCESS_TOKEN
+else
+ RE_AUTHENTICATE
+fi
+
+./$1 --access_token=$ACCESS_TOKEN
\ No newline at end of file
diff --git a/test/cpp/qps/user_data.proto b/test/cpp/qps/user_data.proto
new file mode 100644
index 0000000..9c941ca
--- /dev/null
+++ b/test/cpp/qps/user_data.proto
@@ -0,0 +1,99 @@
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+package UserData;
+
+service UserDataTransfer {
+ // Sends client info
+ rpc RecordSingleClientData (SingleUserRecordRequest) returns (SingleUserRecordReply) {}
+
+ rpc RetrieveSingleUserData (SingleUserRetrieveRequest) returns (SingleUserRetrieveReply) {}
+
+ rpc RetrieveAllUsersData (AllUsersRetrieveRequest) returns (AllUsersRetrieveReply) {}
+}
+
+//Metrics to be stored
+message Metrics {
+ required double qps = 1;
+ required double perc_lat_50 = 2;
+ required double perc_lat_90 = 3;
+ required double perc_lat_95 = 4;
+ required double perc_lat_99 = 5;
+ required double perc_lat_99_point_9 = 6;
+}
+
+//Timestamped details
+message DataDetails {
+ required string timestamp = 1;
+ required Metrics metrics = 2;
+}
+
+//User details
+message UserDetails {
+ required string id = 1;
+ required string name = 2;
+ required string link = 3;
+}
+
+//Stored to database
+message SingleUserDetails {
+ repeated DataDetails data_details = 1;
+ required UserDetails user_details = 2;
+}
+
+//Request for storing a single user's data
+message SingleUserRecordRequest {
+ required string access_token = 1;
+ required Metrics metrics = 2;
+}
+
+//Reply to request for storing single user's data
+message SingleUserRecordReply {
+}
+
+//Request for retrieving single user's data
+message SingleUserRetrieveRequest {
+ required string client_id = 1;
+}
+
+//Reply for request to retrieve single user's data
+message SingleUserRetrieveReply {
+ required SingleUserDetails details = 1;
+}
+
+//Request for retrieving all users' data
+message AllUsersRetrieveReply {
+ repeated SingleUserDetails user_data = 1;
+}
+
+//Reply to request for retrieving all users' data
+message AllUsersRetrieveRequest {
+}
\ No newline at end of file
diff --git a/test/cpp/qps/user_data_client.cc b/test/cpp/qps/user_data_client.cc
new file mode 100644
index 0000000..20ce6d9
--- /dev/null
+++ b/test/cpp/qps/user_data_client.cc
@@ -0,0 +1,100 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "user_data_client.h"
+
+void UserDataClient::setAccessToken(std::string access_token) {
+ access_token_ = access_token;
+}
+
+void UserDataClient::setQPS(double QPS) {
+ QPS_ = QPS;
+ qpsSet = true;
+}
+
+void UserDataClient::setQPSPerCore(double qpsPerCore) {
+ //TBD
+}
+
+void UserDataClient::setLatencies(double percentileLatency50, double percentileLatency90,
+ double percentileLatency95, double percentileLatency99, double percentileLatency99Point9) {
+ percentileLatency50_ = percentileLatency50;
+ percentileLatency90_ = percentileLatency90;
+ percentileLatency95_ = percentileLatency95;
+ percentileLatency99_ = percentileLatency99;
+ percentileLatency99Point9_ = percentileLatency99Point9;
+
+ latenciesSet = true;
+}
+
+void UserDataClient::setTimes(double serverSystemTime, double serverUserTime,
+ double clientSystemTime, double clientUserTime) {
+ //TBD
+}
+
+int UserDataClient::sendDataIfReady() {
+ if(!(qpsSet && latenciesSet))
+ return 0;
+
+ SingleUserRecordRequest singleUserRecordRequest;
+ singleUserRecordRequest.set_access_token(access_token_);
+
+ Metrics* metrics = singleUserRecordRequest.mutable_metrics();
+ metrics->set_qps(QPS_);
+ metrics->set_perc_lat_50(percentileLatency50_);
+ metrics->set_perc_lat_90(percentileLatency90_);
+ metrics->set_perc_lat_95(percentileLatency95_);
+ metrics->set_perc_lat_99(percentileLatency99_);
+ metrics->set_perc_lat_99_point_9(percentileLatency99Point9_);
+
+ SingleUserRecordReply singleUserRecordReply;
+ ClientContext context;
+
+ Status status = stub_->RecordSingleClientData(&context, singleUserRecordRequest, &singleUserRecordReply);
+ if (status.IsOk()) {
+ return 1;
+ } else {
+ return -1;
+ }
+}
+
+// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
+const std::string currentDateTime() {
+ time_t now = time(0);
+ struct tm tstruct;
+ char buf[80];
+ tstruct = *localtime(&now);
+
+ strftime(buf, sizeof(buf), "%Y/%m/%d, %X", &tstruct);
+ return buf;
+}
\ No newline at end of file
diff --git a/test/cpp/qps/user_data_client.h b/test/cpp/qps/user_data_client.h
new file mode 100644
index 0000000..ec3dcb5
--- /dev/null
+++ b/test/cpp/qps/user_data_client.h
@@ -0,0 +1,88 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include <grpc/grpc.h>
+#include <grpc++/channel_arguments.h>
+#include <grpc++/channel_interface.h>
+#include <grpc++/client_context.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/credentials.h>
+#include <grpc++/status.h>
+#include "test/cpp/qps/user_data.grpc.pb.h"
+
+using grpc::ChannelArguments;
+using grpc::ChannelInterface;
+using grpc::ClientContext;
+using grpc::Status;
+using UserData::UserDataTransfer;
+using UserData::Metrics;
+using UserData::SingleUserRecordRequest;
+using UserData::SingleUserRecordReply;
+
+class UserDataClient {
+ public:
+ UserDataClient(std::shared_ptr<ChannelInterface> channel)
+ : stub_(UserDataTransfer::NewStub(channel)) {}
+
+ ~UserDataClient() {}
+
+ void setAccessToken(std::string access_token);
+
+ void setQPS(double QPS);
+
+ void setQPSPerCore(double qpsPerCore);
+
+ void setLatencies(double percentileLatency50, double percentileLatency90,
+ double percentileLatency95, double percentileLatency99, double percentileLatency99Point9);
+
+ void setTimes(double serverSystemTime, double serverUserTime,
+ double clientSystemTime, double clientUserTime);
+
+ int sendDataIfReady();
+
+ private:
+ std::unique_ptr<UserDataTransfer::Stub> stub_;
+ std::string access_token_;
+ double QPS_;
+ double percentileLatency50_;
+ double percentileLatency90_;
+ double percentileLatency95_;
+ double percentileLatency99_;
+ double percentileLatency99Point9_;
+ bool qpsSet = false;
+ bool latenciesSet = false;
+};
\ No newline at end of file
diff --git a/test/cpp/util/benchmark_config.cc b/test/cpp/util/benchmark_config.cc
index 5b3c1da..b688224 100644
--- a/test/cpp/util/benchmark_config.cc
+++ b/test/cpp/util/benchmark_config.cc
@@ -37,6 +37,8 @@
DEFINE_bool(enable_log_reporter, true,
"Enable reporting of benchmark results through GprLog");
+DEFINE_string(access_token, "", "Authorizing JSON string for leaderboard");
+
// In some distros, gflags is in the namespace google, and in some others,
// in gflags. This hack is enabling us to find both.
namespace google {}
@@ -57,6 +59,10 @@
composite_reporter->add(
std::unique_ptr<Reporter>(new GprLogReporter("LogReporter")));
}
+ if(!FLAGS_access_token.empty())
+ composite_reporter->add(
+ std::unique_ptr<Reporter>(new UserDatabaseReporter("UserDataReporter", FLAGS_access_token)));
+
return std::shared_ptr<Reporter>(composite_reporter);
}