Skip to content
Merged
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
15 changes: 15 additions & 0 deletions src/EFCore.Cosmos/Diagnostics/CosmosEventId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ private enum Id
ExecutedCreateItem,
ExecutedReplaceItem,
ExecutedDeleteItem,
ExecutedTransactionalBatch,

// Update events
PrimaryKeyValueNotSet = CoreEventId.ProviderBaseId + 200,
Expand Down Expand Up @@ -114,6 +115,20 @@ public static readonly EventId ExecutedReadNext
public static readonly EventId ExecutedReadItem
= new((int)Id.ExecutedReadItem, CommandPrefix + Id.ExecutedReadItem);

/// <summary>
/// TransactionalBatch was executed.
/// </summary>
/// <remarks>
/// <para>
/// This event is in the <see cref="DbLoggerCategory.Database.Command" /> category.
/// </para>
/// <para>
/// This event uses the <see cref="CosmosTransactionalBatchExecutedEventData" /> payload when used with a <see cref="DiagnosticSource" />.
/// </para>
/// </remarks>
public static readonly EventId ExecutedTransactionalBatch
= new((int)Id.ExecutedTransactionalBatch, CommandPrefix + Id.ExecutedTransactionalBatch);

/// <summary>
/// CreateItem was executed.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Cosmos.Storage.Internal;

namespace Microsoft.EntityFrameworkCore.Diagnostics;

/// <summary>
/// A <see cref="DiagnosticSource" /> event payload class for Cosmos item command executed events.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-diagnostics">Logging, events, and diagnostics</see> for more information and examples.
/// </remarks>
public class CosmosTransactionalBatchExecutedEventData : EventData
{
/// <summary>
/// Constructs the event payload.
/// </summary>
/// <param name="eventDefinition">The event definition.</param>
/// <param name="messageGenerator">A delegate that generates a log message for this event.</param>
/// <param name="elapsed">The time elapsed since the batch was sent to the database.</param>
/// <param name="requestCharge">The request charge in RU.</param>
/// <param name="activityId">The activity ID.</param>
/// <param name="containerId">The ID of the Cosmos container being queried.</param>
/// <param name="partitionKeyValue">The key of the Cosmos partition that the batch is using.</param>
/// <param name="documentIds">The ids of the documents that were written to in the transactional batch.</param>
/// <param name="logSensitiveData">Indicates whether the application allows logging of sensitive data.</param>
public CosmosTransactionalBatchExecutedEventData(
EventDefinitionBase eventDefinition,
Func<EventDefinitionBase, EventData, string> messageGenerator,
TimeSpan elapsed,
double requestCharge,
string activityId,
string containerId,
PartitionKey partitionKeyValue,
string documentIds,
bool logSensitiveData)
: base(eventDefinition, messageGenerator)
{
Elapsed = elapsed;
RequestCharge = requestCharge;
ActivityId = activityId;
ContainerId = containerId;
PartitionKeyValue = partitionKeyValue;
DocumentIds = documentIds;
LogSensitiveData = logSensitiveData;
}

/// <summary>
/// The time elapsed since the command was sent to the database.
/// </summary>
public virtual TimeSpan Elapsed { get; }

/// <summary>
/// The request charge in RU.
/// </summary>
public virtual double RequestCharge { get; }

/// <summary>
/// The activity ID.
/// </summary>
public virtual string ActivityId { get; }

/// <summary>
/// The ID of the Cosmos container being queried.
/// </summary>
public virtual string ContainerId { get; }

/// <summary>
/// The key of the Cosmos partition that the query is using.
/// </summary>
public virtual PartitionKey PartitionKeyValue { get; }

/// <summary>
/// The ids of the documents that were written to in the transactional batch.
/// </summary>
public virtual string DocumentIds { get; }

/// <summary>
/// Indicates whether the application allows logging of sensitive data.
/// </summary>
public virtual bool LogSensitiveData { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,65 @@ private static string ExecutedReadItem(EventDefinitionBase definition, EventData
p.LogSensitiveData ? p.PartitionKeyValue.ToString() : "?");
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public static void ExecutedTransactionalBatch(this IDiagnosticsLogger<DbLoggerCategory.Database.Command> diagnostics,
TimeSpan elapsed,
double requestCharge,
string activityId,
string containerId,
PartitionKey partitionKeyValue,
string documentIds)
{
var definition = CosmosResources.LogExecutedTransactionalBatch(diagnostics);

if (diagnostics.ShouldLog(definition))
{
var logSensitiveData = diagnostics.ShouldLogSensitiveData();
definition.Log(
diagnostics,
elapsed.TotalMilliseconds.ToString(),
requestCharge.ToString(),
activityId,
containerId,
logSensitiveData ? partitionKeyValue.ToString() : "?",
logSensitiveData ? documentIds : "?");
}

if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled))
{
var eventData = new CosmosTransactionalBatchExecutedEventData(
definition,
ExecutedTransactionalBatch,
elapsed,
requestCharge,
activityId,
containerId,
partitionKeyValue,
documentIds,
diagnostics.ShouldLogSensitiveData());

diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
}
}

private static string ExecutedTransactionalBatch(EventDefinitionBase definition, EventData payload)
{
var d = (EventDefinition<string, string, string, string, string, string?>)definition;
var p = (CosmosTransactionalBatchExecutedEventData)payload;
return d.GenerateMessage(
p.Elapsed.Milliseconds.ToString(),
p.RequestCharge.ToString(),
p.ActivityId,
p.ContainerId,
p.LogSensitiveData ? p.DocumentIds.ToString() : "?",
p.LogSensitiveData ? p.PartitionKeyValue.ToString() : "?");
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ public class CosmosLoggingDefinitions : LoggingDefinitions
/// </summary>
public EventDefinitionBase? LogExecutedReadItem;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public EventDefinitionBase? LogExecutedTransactionalBatch;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
Expand Down
37 changes: 37 additions & 0 deletions src/EFCore.Cosmos/Properties/CosmosStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/EFCore.Cosmos/Properties/CosmosStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@
<value>Executed ReplaceItem ({elapsed} ms, {charge} RU) ActivityId='{activityId}', Container='{container}', Id='{id}', Partition='{partitionKey}'</value>
<comment>Information CosmosEventId.ExecutedReplaceItem string string string string string string?</comment>
</data>
<data name="LogExecutedTransactionalBatch" xml:space="preserve">
<value>Executed TransactionalBatch ({elapsed} ms, {charge} RU) ActivityId='{activityId}', Container='{container}', Partition='{partitionKey}', DocumentIds='{documentIds}'</value>
<comment>Information CosmosEventId.ExecutedTransactionalBatch string string string string string string?</comment>
</data>
<data name="LogExecutingReadItem" xml:space="preserve">
<value>Reading resource '{resourceId}' item from container '{containerId}' in partition '{partitionKey}'.</value>
<comment>Information CosmosEventId.ExecutingReadItem string string string?</comment>
Expand Down Expand Up @@ -340,6 +344,12 @@
<data name="ReverseAfterSkipTakeNotSupported" xml:space="preserve">
<value>Reversing the ordering is not supported when limit or offset are already applied.</value>
</data>
<data name="SaveChangesAutoTransactionBehaviorAlwaysAtomicity" xml:space="preserve">
<value>When using AutoTransactionBehavior.Always with the Cosmos DB provider, all changed entities in a SaveChanges call must be in the same collection and partition and not exceed 100 entities to ensure atomicity.</value>
</data>
<data name="SaveChangesAutoTransactionBehaviorAlwaysTriggerAtomicity" xml:space="preserve">
<value>When using AutoTransactionBehavior.Always with the Cosmos DB provider, only 1 entity can be saved at a time when using pre- or post- triggers to ensure atomicity.</value>
</data>
<data name="SingleFirstOrDefaultNotSupportedOnNonNullableQueries" xml:space="preserve">
<value>SingleOrDefault and FirstOrDefault cannot be used Cosmos SQL does not allow Offset without Limit. Consider specifying a 'Take' operation on the query.</value>
</data>
Expand Down
Loading
Loading