Example #1
0
        public async Task <Hipstershop.Cart> GetCartAsync(string userId)
        {
            Log.Information("GetCartAsync called with userId={userId}", userId);
            var   transaction = Elastic.Apm.Agent.Tracer.CurrentTransaction;
            ISpan span        = transaction.StartSpan("GetCartAsync", ApiConstants.TypeDb, ApiConstants.ActionQuery);

            span.Labels["userId"] = userId;
            try
            {
                EnsureRedisConnected();

                var db = redis.GetDatabase();

                // Access the cart from the cache
                var value = await db.HashGetAsync(userId, CART_FIELD_NAME);

                if (!value.IsNull)
                {
                    return(Hipstershop.Cart.Parser.ParseFrom(value));
                }

                // We decided to return empty cart in cases when user wasn't in the cache before
                return(new Hipstershop.Cart());
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Can't access cart storage");
                span.CaptureException(ex);
                throw new RpcException(new Status(StatusCode.FailedPrecondition, $"Can't access cart storage. {ex}"));
            }
            finally {
                span.End();
            }
        }
Example #2
0
        public async Task EmptyCartAsync(string userId)
        {
            Log.Information("EmptyCartAsync called with userId={userId}", userId);
            var   transaction = Elastic.Apm.Agent.Tracer.CurrentTransaction;
            ISpan span        = transaction.StartSpan("EmptyCartAsync", ApiConstants.TypeDb, ApiConstants.ActionQuery);

            span.Labels["userId"] = userId;
            try
            {
                EnsureRedisConnected();
                var db = redis.GetDatabase();

                // Update the cache with empty cart for given user
                await db.HashSetAsync(userId, new[] { new HashEntry(CART_FIELD_NAME, emptyCartBytes) });
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Can't access cart storage");
                span.CaptureException(ex);
                throw new RpcException(new Status(StatusCode.FailedPrecondition, $"Can't access cart storage. {ex}"));
            }
            finally {
                span.End();
            }
        }
Example #3
0
        public async Task AddItemAsync(string userId, string productId, int quantity)
        {
            Log.Information("AddItemAsync called with userId={userId}, productId={productId}, quantity={quantity}", userId, productId, quantity);
            var   transaction = Elastic.Apm.Agent.Tracer.CurrentTransaction;
            ISpan span        = transaction.StartSpan("AddItemAsync", ApiConstants.TypeDb, ApiConstants.ActionQuery);

            span.Labels["userId"]    = userId;
            span.Labels["productId"] = productId;
            span.Labels["quantity"]  = quantity.ToString();
            try
            {
                EnsureRedisConnected();

                var db = redis.GetDatabase();

                // Access the cart from the cache
                var value = await db.HashGetAsync(userId, CART_FIELD_NAME);

                Hipstershop.Cart cart;
                if (value.IsNull)
                {
                    cart        = new Hipstershop.Cart();
                    cart.UserId = userId;
                    cart.Items.Add(new Hipstershop.CartItem {
                        ProductId = productId, Quantity = quantity
                    });
                }
                else
                {
                    cart = Hipstershop.Cart.Parser.ParseFrom(value);
                    var existingItem = cart.Items.SingleOrDefault(i => i.ProductId == productId);
                    if (existingItem == null)
                    {
                        cart.Items.Add(new Hipstershop.CartItem {
                            ProductId = productId, Quantity = quantity
                        });
                    }
                    else
                    {
                        existingItem.Quantity += quantity;
                    }
                }

                await db.HashSetAsync(userId, new[] { new HashEntry(CART_FIELD_NAME, cart.ToByteArray()) });
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Can't access cart storage");
                span.CaptureException(ex);
                throw new RpcException(new Status(StatusCode.FailedPrecondition, $"Can't access cart storage. {ex}"));
            }
            finally {
                span.End();
            }
        }
        internal static void EndSpan(ApmAgent agent, IDbCommand command, ISpan span, Exception exception)
        {
            if (span != null)
            {
                var outcome = Outcome.Success;
                if (exception != null)
                {
                    span.CaptureException(exception);
                    outcome = Outcome.Failure;
                }

                agent.TracerInternal.DbSpanCommon.EndSpan(span, command, outcome);
            }
        }
Example #5
0
        public bool Ping()
        {
            var   transaction = Elastic.Apm.Agent.Tracer.CurrentTransaction;
            ISpan span        = transaction.StartSpan("GetCartAsync", ApiConstants.TypeDb, ApiConstants.ActionQuery);

            try
            {
                var cache = redis.GetDatabase();
                var res   = cache.Ping();
                return(res != TimeSpan.Zero);
            }
            catch (Exception ex)
            {
                span.CaptureException(ex);
                return(false);
            }
            finally {
                span.End();
            }
        }
        /// <summary>
        /// Registers a continuation on the task.
        /// Within the continuation it ends the transaction and captures errors
        /// </summary>
        /// <param name="task">Task.</param>
        /// <param name="transaction">Transaction.</param>
        private void RegisterContinuation(Task task, ISpan span)
        {
            task.ContinueWith((t) =>
            {
                if (t.IsFaulted)
                {
                    if (t.Exception != null)
                    {
                        if (t.Exception is AggregateException aggregateException)
                        {
                            ExceptionFilter.Capture(
                                aggregateException.InnerExceptions.Count == 1
                                    ? aggregateException.InnerExceptions[0]
                                    : aggregateException.Flatten(), span);
                        }
                        else
                        {
                            ExceptionFilter.Capture(t.Exception, span);
                        }
                    }
                    else
                    {
                        span.CaptureError("Task faulted", "A task faulted", new StackTrace().GetFrames());
                    }
                }
                else if (t.IsCanceled)
                {
                    if (t.Exception == null)
                    {
                        span.CaptureError("Task canceled", "A task was canceled", new StackTrace().GetFrames()); //TODO: this async stacktrace is hard to use, make it readable!
                    }
                    else
                    {
                        span.CaptureException(t.Exception);
                    }
                }

                span.End();
            }, System.Threading.CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
        }
        /// <summary>
        /// Helper method used by <see cref="CachedWrapperDelegate{TActionDelegate}"/> to create a delegate
        /// </summary>
        /// <param name="originalHandler">The original delivery report handler </param>
        /// <param name="span">A <see cref="ISpan"/> that can be manipulated when the action is invoked</param>
        /// <typeparam name="TDeliveryReport">Type of the delivery report</typeparam>
        /// <returns>The wrapped action</returns>
        public static Action <TDeliveryReport> WrapAction <TDeliveryReport>(Action <TDeliveryReport> originalHandler, ISpan span) =>
        value =>
        {
            if (value.TryDuckCast <IDeliveryReport>(out var report))
            {
                var isError = report?.Error is not null && report.Error.IsError;
                if (isError)
                {
                    // Set the error manually, as we don't have an exception + stack trace here
                    // Should we create a stack trace manually?
                    var ex = new Exception(report.Error.ToString());
                    span.CaptureException(ex);
                }

                if (report?.Partition is not null)
                {
                    span.SetLabel("partition", report.Partition.ToString());
                }

                // Won't have offset if is error
                if (!isError && report?.Offset is not null)
                {
                    span.SetLabel("offset", report.Offset.ToString());
                }
            }

            // call previous delegate
            try
            {
                originalHandler(value);
            }
            finally
            {
                span.End();
            }
        };
Example #8
0
 internal static bool Capture(Exception e, ISpan span)
 {
     span.CaptureException(e);
     return(false);
 }
Example #9
0
        private static void RegisterError(ISpan span, IApiCallDetails response)
        {
            if (response.Success)
            {
                return;
            }

            var exception = response.OriginalException ?? response.AuditTrail.FirstOrDefault(a => a.Exception != null)?.Exception;
            var f         = PipelineFailure.Unexpected;

            // report inner exception stack traces for these directly if possible
            if (exception is ElasticsearchClientException es)
            {
                f         = es.FailureReason ?? f;
                exception = es.InnerException ?? es;
            }
            if (exception is UnexpectedElasticsearchClientException un)
            {
                f         = un.FailureReason ?? f;
                exception = un.InnerException ?? un;
            }

            var culprit = "Client Error";

            var message     = $"{f.GetStringValue()} {exception?.Message}";
            var stackFrames = exception == null ? null : new StackTrace(exception, true).GetFrames();

            if (stackFrames == null || stackFrames.Length == 0)
            {
                stackFrames = new StackTrace(true).GetFrames();
            }

            var causeOnServer = false;

            if (response.ResponseBodyInBytes != null)
            {
                using var memoryStream = new MemoryStream(response.ResponseBodyInBytes);
                if (ServerError.TryCreate(memoryStream, out var serverError) && serverError != null)
                {
                    causeOnServer = true;
                    culprit       = $"Elasticsearch Server Error: {serverError.Error.Type}";
                    message       = $"The server returned a ({response.HttpStatusCode}) and indicated: " + (
                        serverError.Error?.CausedBy?.Reason
                        ?? serverError.Error?.CausedBy?.Type
                        ?? serverError.Error?.RootCause.FirstOrDefault()?.Reason
                        ?? serverError.Error?.Reason
                        ?? "Response did not indicate a server error, usually means no json was with an error key was returned.");
                }
            }

            if (exception == null && !causeOnServer)
            {
                return;
            }
            if (causeOnServer && string.IsNullOrEmpty(message))
            {
                return;
            }

            if (causeOnServer)
            {
                span.CaptureError(message, culprit, stackFrames);
            }
            else
            {
                span.CaptureException(exception);
            }
        }
 public void Error(Exception ex)
 {
     span?.CaptureException(ex);
 }