//-----------------------------------------------------------------------------
//
// Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// A copy of the License is located at
//
// http://aws.amazon.com/apache2.0
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
//
//-----------------------------------------------------------------------------
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Amazon.Runtime.Internal.Util;
using Amazon.XRay.Recorder.Core.Internal.Entities;
using Amazon.XRay.Recorder.Core.Internal.Utils;
using System.Threading.Tasks;
using EndPoint = Amazon.XRay.Recorder.Core.Internal.Utils.EndPoint;
namespace Amazon.XRay.Recorder.Core.Internal.Emitters
{
///
/// Send the segment to daemon
///
public class UdpSegmentEmitter : ISegmentEmitter
{
private static readonly Logger _logger = Logger.GetLogger(typeof(UdpSegmentEmitter));
private readonly IPAddress _defaultDaemonAddress = IPAddress.Loopback;
private readonly ISegmentMarshaller _marshaller;
private readonly UdpClient _udpClient;
private DaemonConfig _daemonConfig;
private bool _disposed;
///
/// Initializes a new instance of the class.
///
public UdpSegmentEmitter() : this(new JsonSegmentMarshaller())
{
}
private UdpSegmentEmitter(ISegmentMarshaller marshaller)
{
_marshaller = marshaller;
_udpClient = new UdpClient();
_daemonConfig = DaemonConfig.GetEndPoint();
}
///
/// Gets the end point to daemon.
///
/// Two successive calls may not return the same IP as the backing
/// endpoint may be a HostEndpoint that could update.
///
///
public IPEndPoint EndPoint => _daemonConfig.UDPEndpoint;
///
/// Send segment to local daemon
///
/// The segment to be sent
public void Send(Entity segment)
{
try
{
var packet = _marshaller.Marshall(segment);
var data = Encoding.ASCII.GetBytes(packet);
var ip = EndPoint; //Need local var to ensure ip do not updates
_logger.DebugFormat("UDP Segment emitter endpoint: {0}.", ip);
_udpClient.Send(data, data.Length, ip);
}
catch (SocketException e)
{
_logger.Error(e, "Failed to send package through socket.");
}
catch (ArgumentNullException e)
{
_logger.Error(e, "The udp data gram is null.");
}
catch (ObjectDisposedException e)
{
_logger.Error(e, "The udp client is already closed.");
}
catch (InvalidOperationException e)
{
_logger.Error(e, "The udp client connection is invalid.");
}
}
///
/// Sets the daemon address.
/// The daemon address should be in format "IPAddress:Port", i.e. "127.0.0.1:2000"
///
/// The daemon address.
public void SetDaemonAddress(string daemonAddress)
{
if (Environment.GetEnvironmentVariable(DaemonConfig.EnvironmentVariableDaemonAddress) == null)
{
SetEndPointOrDefault(daemonAddress);
}
else
{
_logger.InfoFormat("Ignoring call to SetDaemonAddress as " + DaemonConfig.EnvironmentVariableDaemonAddress + " is set.");
}
}
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Releases unmanaged and - optionally - managed resources.
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
if (_udpClient != null)
{
#if NET45
_udpClient.Close();
#else
_udpClient.Dispose();
#endif
}
_disposed = true;
}
}
private void SetEndPointOrDefault(string daemonAddress)
{
_daemonConfig = DaemonConfig.GetEndPoint(daemonAddress);
}
}
}