Skip to content
This repository has been archived by the owner on Jan 16, 2024. It is now read-only.

Commit

Permalink
Version 1.24.0 alexa-client-sdk
Browse files Browse the repository at this point in the history
Changes in this update:

Feature enhancements, updates, and resolved issues from all releases are available on the [Amazon developer portal](https://developer.amazon.com/docs/alexa/avs-device-sdk/release-notes.html)
  • Loading branch information
Keith Huang committed Jun 4, 2021
1 parent f2dab7e commit e40477e
Show file tree
Hide file tree
Showing 300 changed files with 8,822 additions and 2,331 deletions.
14 changes: 12 additions & 2 deletions ACL/include/ACL/Transport/DownchannelHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <AVSCommon/AVS/Attachment/AttachmentManagerInterface.h>
#include <AVSCommon/Utils/HTTP2/HTTP2RequestSourceInterface.h>
#include <AVSCommon/Utils/Metrics/MetricRecorderInterface.h>
#include <AVSCommon/Utils/Power/PowerResource.h>

#include "ACL/Transport/ExchangeHandler.h"
Expand Down Expand Up @@ -47,22 +48,28 @@ class DownchannelHandler
* @param authToken The token to use to authorize the request.
* @param messageConsumer Object to send decoded messages to.
* @param attachmentManager Object with which to get attachments to write to.
* @param metricRecorder Object with which metrics are logged.
* @return The new DownchannelHandler or nullptr if the operation failed.
*/
static std::shared_ptr<DownchannelHandler> create(
std::shared_ptr<ExchangeHandlerContextInterface> context,
const std::string& authToken,
std::shared_ptr<MessageConsumerInterface> messageConsumer,
std::shared_ptr<avsCommon::avs::attachment::AttachmentManagerInterface> attachmentManager);
std::shared_ptr<avsCommon::avs::attachment::AttachmentManagerInterface> attachmentManager,
const std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface>& metricRecorder);

private:
/**
* Constructor.
*
* @param context The ExchangeContext in which this MessageRequest handler will operate.
* @param authToken The token to use to authorize the request.
* @param metricRecorder The pointer to the recorder used to log metrics.
*/
DownchannelHandler(std::shared_ptr<ExchangeHandlerContextInterface> context, const std::string& authToken);
DownchannelHandler(
std::shared_ptr<ExchangeHandlerContextInterface> context,
const std::string& authToken,
const std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface>& metricRecorder);

/// @name HTTP2RequestSourceInterface methods
/// @{
Expand All @@ -80,6 +87,9 @@ class DownchannelHandler

/// The power resource to prevent device from going to LPM.
std::shared_ptr<avsCommon::utils::power::PowerResource> m_powerResource;

/// The recorder used to log metrics.
std::shared_ptr<avsCommon::utils::metrics::MetricRecorderInterface> m_metricRecorder;
};

} // namespace acl
Expand Down
69 changes: 65 additions & 4 deletions ACL/src/Transport/DownchannelHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include <sstream>

#include <AVSCommon/Utils/HTTP/HttpResponseCode.h>
#include <AVSCommon/Utils/HTTP2/HTTP2MimeResponseDecoder.h>
#include <AVSCommon/Utils/Logger/Logger.h>
#include <AVSCommon/Utils/Power/PowerMonitor.h>
#include <AVSCommon/Utils/Metrics/DataPointCounterBuilder.h>
#include <AVSCommon/Utils/Metrics/MetricEventBuilder.h>

#include "ACL/Transport/DownchannelHandler.h"
#include "ACL/Transport/HTTP2Transport.h"
Expand All @@ -27,6 +30,7 @@ namespace acl {

using namespace avsCommon::utils::http;
using namespace avsCommon::utils::http2;
using namespace avsCommon::utils::metrics;
using namespace avsCommon::utils::power;

/// Downchannel URL
Expand All @@ -41,18 +45,72 @@ static const std::chrono::seconds ESTABLISH_CONNECTION_TIMEOUT = std::chrono::se
/// String to identify log entries originating from this file.
static const std::string TAG("DownchannelHandler");

/// String to identify the metric source prefix for @c DownChannelHandler.
static const std::string METRIC_SOURCE_PREFIX = "DOWNCHANNEL_HANDLER-";

/// String to identify the response finished metric.
static const std::string RESPONSE_FINISHED = "RESPONSE_FINISHED";

/**
* Create a LogEntry using this file's TAG and the specified event string.
*
* @param The event string for this @c LogEntry.
*/
#define LX(event) alexaClientSDK::avsCommon::utils::logger::LogEntry(TAG, event)

/**
* Creates a MetricEvent with the given event name and datapoint and submits it with the metric recorder.
* @param metricRecorder - The @c MetricRecorderInterface used log the metric.
* @param eventName - The event name of the metric to be logged.
* @param dataPoint - The @c DataPoint to be added to the metric.
*/
void submitMetric(
const std::shared_ptr<MetricRecorderInterface>& metricRecorder,
const std::string& eventName,
const DataPoint& dataPoint) {
auto metricEvent =
MetricEventBuilder{}.setActivityName(METRIC_SOURCE_PREFIX + eventName).addDataPoint(dataPoint).build();

if (!metricEvent) {
ACSDK_ERROR(LX("submitMetricFailed").d("reason", "invalid metric event"));
return;
}

recordMetric(metricRecorder, metricEvent);
}

/**
* Submits a metric when the downchannel stream is closed either because it is closed from the server, due to internal
* error or due to timeouts.
*
* @param metricRecorder The pointer to the metric recorder used to log the metric.
* @param status The @c HTTP2ResponseFinishedStatus status with which the downchannel stream is closed.
*/
void submitResponseFinishedMetric(
const std::shared_ptr<MetricRecorderInterface>& metricRecorder,
HTTP2ResponseFinishedStatus status) {
if (!metricRecorder) {
return;
}

/// Not logging cancelled metric because this could be triggered by user with a shutdown.
if (HTTP2ResponseFinishedStatus::CANCELLED == status) {
return;
}

std::stringstream ss;
ss << status;
auto dataPoint = DataPointCounterBuilder{}.setName(ss.str()).increment(1).build();

submitMetric(metricRecorder, RESPONSE_FINISHED, dataPoint);
}

std::shared_ptr<DownchannelHandler> DownchannelHandler::create(
std::shared_ptr<ExchangeHandlerContextInterface> context,
const std::string& authToken,
std::shared_ptr<MessageConsumerInterface> messageConsumer,
std::shared_ptr<avsCommon::avs::attachment::AttachmentManagerInterface> attachmentManager) {
std::shared_ptr<avsCommon::avs::attachment::AttachmentManagerInterface> attachmentManager,
const std::shared_ptr<MetricRecorderInterface>& metricRecorder) {
ACSDK_DEBUG9(LX(__func__).d("context", context.get()));

if (!context) {
Expand All @@ -65,7 +123,7 @@ std::shared_ptr<DownchannelHandler> DownchannelHandler::create(
return nullptr;
}

std::shared_ptr<DownchannelHandler> handler(new DownchannelHandler(context, authToken));
std::shared_ptr<DownchannelHandler> handler(new DownchannelHandler(context, authToken, metricRecorder));

HTTP2RequestConfig cfg{
HTTP2RequestType::GET, context->getAVSGateway() + AVS_DOWNCHANNEL_URL_PATH_EXTENSION, DOWNCHANNEL_ID_PREFIX};
Expand Down Expand Up @@ -97,8 +155,10 @@ HTTP2SendDataResult DownchannelHandler::onSendData(char* bytes, size_t size) {

DownchannelHandler::DownchannelHandler(
std::shared_ptr<ExchangeHandlerContextInterface> context,
const std::string& authToken) :
ExchangeHandler{context, authToken} {
const std::string& authToken,
const std::shared_ptr<MetricRecorderInterface>& metricRecorder) :
ExchangeHandler{context, authToken},
m_metricRecorder{metricRecorder} {
ACSDK_DEBUG9(LX(__func__).d("context", context.get()));
m_powerResource = PowerMonitor::getInstance()->createLocalPowerResource(TAG);
if (m_powerResource) {
Expand Down Expand Up @@ -147,6 +207,7 @@ bool DownchannelHandler::onReceiveResponseCode(long responseCode) {
void DownchannelHandler::onResponseFinished(HTTP2ResponseFinishedStatus status, const std::string& nonMimeBody) {
ACSDK_DEBUG5(LX(__func__).d("status", status).d("nonMimeBody", nonMimeBody));
m_context->onDownchannelFinished();
submitResponseFinishedMetric(m_metricRecorder, status);
}

} // namespace acl
Expand Down
101 changes: 96 additions & 5 deletions ACL/src/Transport/HTTP2Transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include <AVSCommon/Utils/Error/FinallyGuard.h>
#include <AVSCommon/Utils/HTTP2/HTTP2MimeRequestEncoder.h>
#include <AVSCommon/Utils/Logger/Logger.h>
#include <AVSCommon/Utils/Metrics/MetricEventBuilder.h>
#include <AVSCommon/Utils/Metrics/DataPointCounterBuilder.h>
#include <AVSCommon/Utils/Power/PowerMonitor.h>
#include <ACL/Transport/PostConnectInterface.h>

Expand All @@ -37,6 +39,7 @@ using namespace avsCommon::avs;
using namespace avsCommon::avs::attachment;
using namespace avsCommon::utils::error;
using namespace avsCommon::utils::http2;
using namespace avsCommon::utils::metrics;
using namespace avsCommon::utils::power;

/// String to identify log entries originating from this file.
Expand Down Expand Up @@ -70,6 +73,85 @@ static std::chrono::minutes INACTIVITY_TIMEOUT{5};
/// Max time a @c MessageRequest should linger unprocessed before it should be consider TIMEDOUT.
static const std::chrono::seconds MESSAGE_QUEUE_TIMEOUT = std::chrono::seconds(15);

/// Prefix used to identify metrics published by this module.
static const std::string HTTP2TRANSPORT_METRIC_SOURCE_PREFIX = "HTTP2TRANSPORT-";

/// Metric identifier for message send error.
static const std::string MESSAGE_SEND_ERROR = "ERROR.MESSAGE_SEND_FAILED";

/// Metric identifier for disconnect reason.
static const std::string DISCONNECT_REASON = "DISCONNECT_REASON";

/**
* Capture metric for Disconnects along with Disconnect reason.
*
* @param metricRecorder The metric recorder object.
* @param reason The @c ConnectionStatusObserverInterface::ChangedReason for disconnection.
*/
static void submitDisconnectReasonMetric(
const std::shared_ptr<MetricRecorderInterface>& metricRecorder,
ConnectionStatusObserverInterface::ChangedReason reason) {
if (!metricRecorder) {
return;
}

if (ConnectionStatusObserverInterface::ChangedReason::SUCCESS == reason ||
ConnectionStatusObserverInterface::ChangedReason::ACL_CLIENT_REQUEST == reason) {
return;
}

std::stringstream ss;
ss << reason;

auto metricEvent = MetricEventBuilder{}
.setActivityName(HTTP2TRANSPORT_METRIC_SOURCE_PREFIX + DISCONNECT_REASON)
.addDataPoint(DataPointCounterBuilder{}.setName(ss.str()).increment(1).build())
.build();

if (!metricEvent) {
ACSDK_ERROR(LX("submitDisconnectReasonMetricFailed").d("reason", "invalid metric event"));
return;
}

recordMetric(metricRecorder, metricEvent);
}

/**
* Capture metric for cases where there are internal message send errors or timeouts.
*
* @param metricRecorder The metric recorder object.
* @param status The @c MessageRequestObserverInterface::Status of the message.
*/
static void submitMessageSendErrorMetric(
const std::shared_ptr<MetricRecorderInterface>& metricRecorder,
MessageRequestObserverInterface::Status status) {
if (!metricRecorder) {
return;
}

std::stringstream ss;
switch (status) {
case MessageRequestObserverInterface::Status::INTERNAL_ERROR:
case MessageRequestObserverInterface::Status::TIMEDOUT:
ss << status;
break;
default:
return;
}

auto metricEvent = MetricEventBuilder{}
.setActivityName(HTTP2TRANSPORT_METRIC_SOURCE_PREFIX + MESSAGE_SEND_ERROR)
.addDataPoint(DataPointCounterBuilder{}.setName(ss.str()).increment(1).build())
.build();

if (!metricEvent) {
ACSDK_ERROR(LX("submitMessageSendErrorMetricFailed").d("reason", "invalid metric event"));
return;
}

recordMetric(metricRecorder, metricEvent);
}

/**
* Write a @c HTTP2Transport::State value to an @c ostream as a string.
*
Expand Down Expand Up @@ -336,7 +418,9 @@ void HTTP2Transport::sendMessage(std::shared_ptr<MessageRequest> request) {
} else {
ACSDK_ERROR(LX_P("enqueueRequestFailed").d("reason", "notInAllowedState").d("m_state", m_state));
lock.unlock();
request->sendCompleted(MessageRequestObserverInterface::Status::NOT_CONNECTED);
auto status = MessageRequestObserverInterface::Status::NOT_CONNECTED;
request->sendCompleted(status);
submitMessageSendErrorMetric(m_metricRecorder, status);
}
}

Expand Down Expand Up @@ -638,8 +722,8 @@ HTTP2Transport::State HTTP2Transport::handleConnecting() {
return m_state;
}

auto downchannelHandler =
DownchannelHandler::create(shared_from_this(), authToken, m_messageConsumer, m_attachmentManager);
auto downchannelHandler = DownchannelHandler::create(
shared_from_this(), authToken, m_messageConsumer, m_attachmentManager, m_metricRecorder);

if (!downchannelHandler) {
ACSDK_ERROR(LX_P("handleConnectingFailed").d("reason", "createDownchannelHandlerFailed"));
Expand Down Expand Up @@ -688,6 +772,8 @@ HTTP2Transport::State HTTP2Transport::handleConnected() {
HTTP2Transport::State HTTP2Transport::handleServerSideDisconnect() {
ACSDK_INFO(LX_P(__func__));
notifyObserversOnServerSideDisconnect();
submitDisconnectReasonMetric(
m_metricRecorder, ConnectionStatusObserverInterface::ChangedReason::SERVER_SIDE_DISCONNECT);
return State::DISCONNECTING;
}

Expand Down Expand Up @@ -722,6 +808,7 @@ HTTP2Transport::State HTTP2Transport::handleShutdown() {
m_http2Connection->disconnect();

notifyObserversOnDisconnect(m_disconnectReason);
submitDisconnectReasonMetric(m_metricRecorder, m_disconnectReason);

return State::SHUTDOWN;
}
Expand All @@ -747,7 +834,9 @@ HTTP2Transport::State HTTP2Transport::monitorSharedQueueWhileWaiting(
}

auto request = m_sharedRequestQueue->dequeueOldestRequest();
request->sendCompleted(MessageRequestObserverInterface::Status::TIMEDOUT);
auto status = MessageRequestObserverInterface::Status::TIMEDOUT;
request->sendCompleted(status);
submitMessageSendErrorMetric(m_metricRecorder, status);
}

auto messageRequestTime = m_sharedRequestQueue->peekRequestTime();
Expand Down Expand Up @@ -811,7 +900,9 @@ HTTP2Transport::State HTTP2Transport::sendMessagesAndPings(
m_eventTracer,
m_requestActivityPowerResource);
if (!handler) {
messageRequest->sendCompleted(MessageRequestObserverInterface::Status::INTERNAL_ERROR);
auto status = MessageRequestObserverInterface::Status::INTERNAL_ERROR;
messageRequest->sendCompleted(status);
submitMessageSendErrorMetric(m_metricRecorder, status);
}
} else {
ACSDK_ERROR(LX_P("failedToCreateMessageHandler").d("reason", "invalidAuth"));
Expand Down

0 comments on commit e40477e

Please sign in to comment.