Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions csharp/src/Apache.Arrow.Adbc/Tracing/ActivityExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public static class ActivityExtensions
/// <param name="eventName">The name of the event.</param>
/// <param name="tags">The optional list of tags to attach to the event.</param>
/// <returns><see langword="this"/> for convenient chaining.</returns>
[Obsolete("This method is deprecated. Please use the methods from ActivityWithPii, instead.")]
public static Activity? AddEvent(this Activity? activity, string eventName, IReadOnlyList<KeyValuePair<string, object?>>? tags = default)
{
if (activity == null) return activity;
Expand All @@ -43,6 +44,7 @@ public static class ActivityExtensions
/// <param name="traceParent">The traceParent id for the associated <see cref="ActivityContext"/>.</param>
/// <param name="tags">The optional list of tags to attach to the event.</param>
/// <returns><see langword="this"/> for convenient chaining.</returns>
[Obsolete("This method is deprecated. Please use the methods from ActivityWithPii, instead.")]
public static Activity? AddLink(this Activity? activity, string traceParent, IReadOnlyList<KeyValuePair<string, object?>>? tags = default)
{
if (activity == null) return activity;
Expand All @@ -58,6 +60,7 @@ public static class ActivityExtensions
/// <returns><see langword="this" /> for convenient chaining.</returns>
/// <param name="key">The tag key name as a function</param>
/// <param name="value">The tag value mapped to the input key as a function</param>
[Obsolete("This method is deprecated. Please use the methods from ActivityWithPii, instead.")]
public static Activity? AddTag(this Activity? activity, string key, Func<object?> value)
{
return activity?.AddTag(key, value());
Expand All @@ -72,6 +75,7 @@ public static class ActivityExtensions
/// <param name="key">The tag key name as a function</param>
/// <param name="value">The tag value mapped to the input key</param>
/// /// <param name="condition">The condition to check before adding the tag</param>
[Obsolete("This method is deprecated. Please use the methods from ActivityWithPii, instead.")]
public static Activity? AddConditionalTag(this Activity? activity, string key, string? value, bool condition)
{
if (condition)
Expand All @@ -91,6 +95,7 @@ public static class ActivityExtensions
/// <param name="key">The tag key name</param>
/// <param name="value">The tag value mapped to the input key as a function</param>
/// <param name="guidFormat">The format indicator for 16-byte GUID arrays.</param>
[Obsolete("This method is deprecated. Please use the methods from ActivityWithPii, instead.")]
public static Activity? AddTag(this Activity? activity, string key, byte[]? value, string? guidFormat)
{
if (value == null)
Expand Down
226 changes: 226 additions & 0 deletions csharp/src/Apache.Arrow.Adbc/Tracing/ActivityTrace.cs

Large diffs are not rendered by default.

331 changes: 331 additions & 0 deletions csharp/src/Apache.Arrow.Adbc/Tracing/ActivityWithPii.cs

Large diffs are not rendered by default.

108 changes: 108 additions & 0 deletions csharp/src/Apache.Arrow.Adbc/Tracing/IActivityTracerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ namespace Apache.Arrow.Adbc.Tracing
{
public static class IActivityTracerExtensions
{
#region Obsolete methods

/// <summary>
/// Invokes the delegate within the context of a new started <see cref="Activity"/>.
/// </summary>
Expand All @@ -37,6 +39,7 @@ public static class IActivityTracerExtensions
/// status is set to <see cref="ActivityStatusCode.Error"/> and an Activity <see cref="ActivityEvent"/> is added to the activity
/// and finally the exception is rethrown.
/// </remarks>
[Obsolete("This method is deprecated. Please use TraceActivity overloads that take ActivityWithPii instead of Activity to avoid accidentally logging PII data.")]
public static void TraceActivity(this IActivityTracer tracer, Action<Activity?> call, [CallerMemberName] string? activityName = default, string? traceParent = default)
{
tracer.Trace.TraceActivity(call, activityName, traceParent ?? tracer.TraceParent);
Expand All @@ -56,6 +59,7 @@ public static void TraceActivity(this IActivityTracer tracer, Action<Activity?>
/// If an exception is thrown by the delegate, the Activity status is set to <see cref="ActivityStatusCode.Error"/>
/// and an Event <see cref="ActivityEvent"/> is added to the activity and finally the exception is rethrown.
/// </remarks>
[Obsolete("This method is deprecated. Please use TraceActivity overloads that take ActivityWithPii instead of Activity to avoid accidentally logging PII data.")]
public static T TraceActivity<T>(this IActivityTracer tracer, Func<Activity?, T> call, [CallerMemberName] string? activityName = null, string? traceParent = null)
{
Type type = typeof(T);
Expand All @@ -80,6 +84,7 @@ public static T TraceActivity<T>(this IActivityTracer tracer, Func<Activity?, T>
/// If an exception is thrown by the delegate, the Activity status is set to <see cref="ActivityStatusCode.Error"/>
/// and an Event <see cref="ActivityEvent"/> is added to the activity and finally the exception is rethrown.
/// </remarks>
[Obsolete("This method is deprecated. Please use TraceActivity overloads that take ActivityWithPii instead of Activity to avoid accidentally logging PII data.")]
public static Task TraceActivityAsync(this IActivityTracer tracer, Func<Activity?, Task> call, [CallerMemberName] string? activityName = null, string? traceParent = null)
{
return tracer.Trace.TraceActivityAsync(call, activityName, traceParent ?? tracer.TraceParent);
Expand All @@ -99,9 +104,112 @@ public static Task TraceActivityAsync(this IActivityTracer tracer, Func<Activity
/// If an exception is thrown by the delegate, the Activity status is set to <see cref="ActivityStatusCode.Error"/>
/// and an Event <see cref="ActivityEvent"/> is added to the activity and finally the exception is rethrown.
/// </remarks>
[Obsolete("This method is deprecated. Please use TraceActivity overloads that take ActivityWithPii instead of Activity to avoid accidentally logging PII data.")]
public static Task<T> TraceActivityAsync<T>(this IActivityTracer tracer, Func<Activity?, Task<T>> call, [CallerMemberName] string? activityName = null, string? traceParent = null)
{
return tracer.Trace.TraceActivityAsync(call, activityName, traceParent ?? tracer.TraceParent);
}

#endregion

/// <summary>
/// Invokes the delegate within the context of a new started <see cref="ActivityWithPii"/>.
/// </summary>
/// <param name="call">The delegate to call within the context of a newly started <see cref="ActivityWithPii"/></param>
/// <param name="methodName">The name of the method for the activity.</param>
/// <returns>Returns a new <see cref="ActivityWithPii"/> object if there is any listener to the Activity, returns null otherwise</returns>
/// <remarks>
/// Creates and starts a new <see cref="ActivityWithPii"/> object if there is any listener for the ActivitySource.
/// Passes the Activity to the delegate and invokes the delegate. If there are no exceptions thrown by the delegate the
/// Activity status is set to <see cref="ActivityStatusCode.Ok"/>. If an exception is thrown by the delegate, the Activity
/// status is set to <see cref="ActivityStatusCode.Error"/> and an Activity <see cref="ActivityEvent"/> is added to the activity
/// and finally the exception is rethrown.
/// </remarks>
public static void TraceActivity(
this IActivityTracer tracer,
Action<ActivityWithPii?> call,
[CallerMemberName] string? activityName = default,
string? traceParent = default,
bool exceptionHasPii = true)
{
tracer.Trace.TraceActivity(call, activityName, traceParent ?? tracer.TraceParent, exceptionHasPii);
}

/// <summary>
/// Invokes the delegate within the context of a new started <see cref="ActivityWithPii"/>.
/// </summary>
/// <typeparam name="T">The return type for the delegate.</typeparam>
/// <param name="call">The delegate to call within the context of a newly started <see cref="ActivityWithPii"/></param>
/// <param name="methodName">The name of the method for the activity.</param>
/// <returns>The result of the call to the delegate.</returns>
/// <remarks>
/// Creates and starts a new <see cref="ActivityWithPii"/> object if there is any listener for the ActivitySource.
/// Passes the Activity to the delegate and invokes the delegate. If there are no exceptions thrown by the delegate the
/// Activity status is set to <see cref="ActivityStatusCode.Ok"/> and the result is returned.
/// If an exception is thrown by the delegate, the Activity status is set to <see cref="ActivityStatusCode.Error"/>
/// and an Event <see cref="ActivityEvent"/> is added to the activity and finally the exception is rethrown.
/// </remarks>
public static T TraceActivity<T>(
this IActivityTracer tracer,
Func<ActivityWithPii?, T> call,
[CallerMemberName] string? activityName = null,
string? traceParent = null,
bool exceptionHasPii = true)
{
Type type = typeof(T);
if (type == typeof(Task) || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Task<>)))
{
throw new InvalidOperationException($"Invalid return type ('{type.Name}') for synchronous method call. Please use {nameof(TraceActivityAsync)}");
}

return tracer.Trace.TraceActivity(call, activityName, traceParent ?? tracer.TraceParent, exceptionHasPii);
}

/// <summary>
/// Invokes the delegate within the context of a new started <see cref="ActivityWithPii"/>.
/// </summary>
/// <param name="call">The delegate to call within the context of a newly started <see cref="ActivityWithPii"/></param>
/// <param name="methodName">The name of the method for the activity.</param>
/// <returns></returns>
/// <remarks>
/// Creates and starts a new <see cref="ActivityWithPii"/> object if there is any listener for the ActivitySource.
/// Passes the Activity to the delegate and invokes the delegate. If there are no exceptions thrown by the delegate the
/// Activity status is set to <see cref="ActivityStatusCode.Ok"/> and the result is returned.
/// If an exception is thrown by the delegate, the Activity status is set to <see cref="ActivityStatusCode.Error"/>
/// and an Event <see cref="ActivityEvent"/> is added to the activity and finally the exception is rethrown.
/// </remarks>
public static Task TraceActivityAsync(
this IActivityTracer tracer,
Func<ActivityWithPii?, Task> call,
[CallerMemberName] string? activityName = null,
string? traceParent = null,
bool exceptionHasPii = true)
{
return tracer.Trace.TraceActivityAsync(call, activityName, traceParent ?? tracer.TraceParent, exceptionHasPii);
}

/// <summary>
/// Invokes the delegate within the context of a new started <see cref="ActivityWithPii"/>.
/// </summary>
/// <typeparam name="T">The return type for the delegate.</typeparam>
/// <param name="call">The delegate to call within the context of a newly started <see cref="ActivityWithPii"/></param>
/// <param name="methodName">The name of the method for the activity.</param>
/// <returns>The result of the call to the delegate.</returns>
/// <remarks>
/// Creates and starts a new <see cref="ActivityWithPii"/> object if there is any listener for the ActivitySource.
/// Passes the Activity to the delegate and invokes the delegate. If there are no exceptions thrown by the delegate the
/// Activity status is set to <see cref="ActivityStatusCode.Ok"/> and the result is returned.
/// If an exception is thrown by the delegate, the Activity status is set to <see cref="ActivityStatusCode.Error"/>
/// and an Event <see cref="ActivityEvent"/> is added to the activity and finally the exception is rethrown.
/// </remarks>
public static Task<T> TraceActivityAsync<T>(
this IActivityTracer tracer,
Func<ActivityWithPii?, Task<T>> call,
[CallerMemberName] string? activityName = null,
string? traceParent = null,
bool exceptionHasPii = true)
{
return tracer.Trace.TraceActivityAsync(call, traceParent ?? tracer.TraceParent, activityName, exceptionHasPii);
}
}
}
51 changes: 51 additions & 0 deletions csharp/src/Apache.Arrow.Adbc/Tracing/RedactedValue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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.Text.Json.Serialization;

namespace Apache.Arrow.Adbc.Tracing
{
/// <summary>
/// Stores a value that should be redacted when converted to string or serialized to JSON.
/// The value can still be retrieved using the GetValue method.
/// </summary>
/// <param name="value"></param>
[JsonConverter(typeof(ToStringJsonConverter<RedactedValue>))]
public class RedactedValue(object? value)
{
private readonly object? _value = value;

public const string DefaultValue = "[REDACTED]";

/// <summary>
/// Returns a string representation of the redacted value. This will always return the default value <see cref="DefaultValue"/>
/// regardless of the actual value stored in the object.
/// </summary>
/// <returns></returns>
public override string ToString() => DefaultValue;

/// <summary>
/// Gets the actual value stored in the object. This method can be used to retrieve the original value if needed,
/// but it should be used with caution as it may contain sensitive information.
/// </summary>
/// <returns></returns>
public object? GetValue()
{
return _value;
}
}
}
40 changes: 40 additions & 0 deletions csharp/src/Apache.Arrow.Adbc/Tracing/ToStringJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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.Text.Json;
using System.Text.Json.Serialization;

namespace Apache.Arrow.Adbc.Tracing
{
/// <summary>
/// Converts an object to a JSON string using its ToString() method.
/// This is useful for types that do not have a default JSON converter
/// or when you want to control how the object is represented in JSON.
/// </summary>
/// <typeparam name="T"></typeparam>
public class ToStringJsonConverter<T> : JsonConverter<T>
{
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
throw new NotImplementedException();

public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions _)
{
writer.WriteStringValue(value?.ToString());
}
}
}
Loading
Loading