Dan Csharpster
Dan Csharpster

Reputation: 2732

Troubleshooting Cassandra C# driver, including seeing CQL statements

We have a ASP.NET 4.5 webapi solution, which writes data to Cassandra. We are having an issue with a delete operation not working. We'd like to see what is going on with the C# driver under the hood. We've set the CassandraTraceSwitch to Verbose, but it doesn't give much useful data. I'd like to see the actual queries it's generating and executing against Cassandra, as well as the response it gets back.

Upvotes: 2

Views: 663

Answers (2)

Stanislav Berkov
Stanislav Berkov

Reputation: 6287

Just as an idea. It does not fully answer original question but might help. You can create DispatchProxy and intercept CQL queries. I do it this way

using Cassandra;
using System;
using System.Reflection;
using Cassandra.Data.Linq;
using Wpfe.Logging;
using Microsoft.Extensions.Logging;
using System.Diagnostics;

namespace Wpfe.Storage {
    public class QueryTracingProxy<T> : DispatchProxy where T : class {
        private static readonly ILogger _logger = AppLogFactory.CreateLogger("Wpfe.StorageQuery");
        static Lazy<PropertyInfo> cqlPropertyInfo = new Lazy<PropertyInfo>(
            () => typeof(PreparedStatement).GetProperty("Cql", BindingFlags.NonPublic | BindingFlags.Instance));

        public T Target { get; private set; }

        public static T Decorate(T target) {
            var proxy = Create<T, QueryTracingProxy<T>>() as QueryTracingProxy<T>;
            proxy.Target = target;
            return proxy as T;
        }

        [DebuggerStepThrough]
        protected override object Invoke(MethodInfo targetMethod, object[] args) {
            try {
                if (targetMethod.Name.Equals(nameof(ISession.Execute))) {
                    if (args.Length > 0) {
                        var arg1 = args[0];
                        if (arg1 is string) {
                            var str = (string)arg1;
                            _logger.LogInformation(str);
                        }
                        else if (arg1 is CqlCommand) {
                            var cmd = (CqlCommand)arg1;
                            var values = string.Join("\n", cmd.QueryValues);
                            _logger.LogInformation(string.Concat(cmd.QueryString, "\n", values));
                        }
                    }
                }
                else if (targetMethod.Name.Equals(nameof(ISession.ExecuteAsync)) && args.Length == 1) {
                    var statement = args[0] as BoundStatement;
                    if (statement != null) {
                        var preparedStatement = statement.PreparedStatement;
                        if (preparedStatement != null) {
                            var cql = cqlPropertyInfo.Value.GetValue(preparedStatement);
                            var values = string.Join("\n", statement.QueryValues);
                            _logger.LogInformation(string.Concat(cql, "\n", values));
                        }
                    }
                }

                var result = targetMethod.Invoke(Target, args);
                return result;
            }
            catch (TargetInvocationException exc) {
                throw exc.InnerException;
            }
        }
    }

    public static class QueryTracer {
        private static readonly ILogger _logger = AppLogFactory.CreateLogger("Wpfe.StorageQuery");
        public static ISession HookUp(ISession session) {
            if (_logger.IsEnabled(LogLevel.Information) || _logger.IsEnabled(LogLevel.Debug)) {
                var proxy = QueryTracingProxy<ISession>.Decorate(session);
                return proxy;
            }
            return session;
        }
    }
}

Then in code I just decorate ISession instance, i.e.

private static ISession createDefaultSession() {
   var cluster = EntityManagerFactory.BuildCluster(StorageGlobalOptions.Value.DatabaseEffective);
   var session = cluster.Connect();
   return QueryTracer.HookUp(session);
}

Upvotes: 1

jorgebg
jorgebg

Reputation: 6600

There is no way to output the query generated, but it is a good idea.

I've created a ticket to include the generated query in the output when the trace level is Verbose, you can follow the progress on JIRA or send a pull request for it.

Upvotes: 4

Related Questions