Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add logging infra to PineconeClient and Index. #126

Merged
merged 3 commits into from
Sep 18, 2024

Conversation

maumar
Copy link
Contributor

@maumar maumar commented Jul 24, 2024

The idea is, each operation has a pair of log entries - start is logged at Trace level (and should be ignored in most cases), and then we either log success at Debug level, or error at Error level. Only logging basic information like operation type and the index name - we want to avoid printing sensitive data in the logs for security reasons.

Also wired up logger(factory) to GrpcChannel and HttpClient for more detailed logging.

Fixes #118

LoggerFactory = loggerFactory;
Logger = loggerFactory?.CreateLogger<PineconeClient>() ?? (ILogger)NullLogger.Instance;

var httpClientLogger = loggerFactory?.CreateLogger<HttpClient>() ?? (ILogger)NullLogger.Instance;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if this is the right way to do this

@maumar maumar force-pushed the add_logging_support branch 3 times, most recently from ca3e0c8 to af84803 Compare July 24, 2024 06:23
The idea is, each operation has a pair of log entries - start is logged at Trace level (and should be ignored in most cases), and then we either log success at Debug level, or error at Error level.
Only logging basic information like operation type and the index name - we want to avoid printing sensitive data in the logs for security reasons.

Also wired up logger(factory) to GrpcChannel and HttpClient for more detailed logging.

Fixes neon-sunset#118
@neon-sunset
Copy link
Owner

neon-sunset commented Jul 25, 2024

Apparently I'm down with COVID or similar and will get to this in a couple days. Thanks!

Edit: it turned out to be way worse, but now I'm in a working condition and will review this soon.

@maumar
Copy link
Contributor Author

maumar commented Jul 25, 2024

@neon-sunset get well soon! I'm planning to take a look at ReadOnlyMemory<float> improvement as well and can do that in parallel to this work, so no rush.

- Remove excessive logging for now (tentative)
- Skip .Trace log level in tests which outputs sensitive http headers
- Introduce exception types  to preserve and expose partial success state on parallel batch operation failure
- Remove dependency on CommunityToolkit.Diagnostics
@neon-sunset neon-sunset added this to the 3.0 milestone Sep 16, 2024
@neon-sunset
Copy link
Owner

neon-sunset commented Sep 16, 2024

@maumar I have investigated the issue with credentials leakage as discussed and could not reproduce it with gRPC stack - it is generally well-behaved if, as you noted, chatty, and does not output sensitive details about payload or metadata.

Regarding explicit logging within client and transports/index - I'm slightly on the fence about it. When looking at it without context the logging from purely gRPC and HttpClient themselves seems insufficient. At the same time, I have quite a bit of experience doing incident response and L3 support where these extra "Operation Started"+"Operation Completed/Failed" pairs have only ever added to visual noise when looking through logs and increased log storage bill - most of the time, you only ever care about innermost failure message that contains exception details, and we're bubbling up exceptions to the caller therefore this will end up being eventually observed and logged by users who care about this.

For now, I decided to try out a sample application where only "interesting" parts are logged, which is only one thing for now - parallel batch operations.

While stress-testing these I discovered that Pinecone has quite stringent payload size limits, so I want to flesh this feature out a bit more before doing a release - there's a 1k IDs limit on Delete request, so it must have parallel batching too. This is not just a nice to have but an actual issue users will and likely have already run into when working with large amounts of vectors without batching.

Regarding official/Fern's Pinecone SDK at https://github.com/pinecone-io/pinecone-dotnet-client/https://www.nuget.org/packages/Pinecone.Client - it was indeed released. However, for now it has a few issues which I believe make it worth continuing to develop Pinecone.NET:

It is, however, more customizable w.r.t. timeout, retries configuration and other gRPC settings but this can be addressed if current defaults pose issues to end users.

- Redact API key from logged headers
- Match request headers behavior of the official clients
- Add support for client-side gRPC load balancing (it does not help much because Pinecone uses a misconfigured reverse-proxy that has barely any streams over a single H2 connection)
- Add batching and parallelization to Delete(vectors)
- Update dependencies
@neon-sunset
Copy link
Owner

neon-sunset commented Sep 18, 2024

I think it can be merged in the current form, I have also added redact options to logging message handler so that the API key is now filtered regardless of the logging level. In any case, thank you for pointing this out previously and for contributing this PR.

Will work on remaining items I think that should get to 3.0.

Also want to investigate the gRPC performance issues some more - it seems that Pinecone's reverse-proxy is poorly configured and allows very few concurrent streams over a single H2 connection. I have partially mitigated it by adding support for client-side load balancing but it's not enough. I have also tried a toy GrpcChannel pool but it did not measurably improve performance. It might be a grpc-dotnet issue still but given that it's performance sensitive, I'm less inclined to think it's at fault and attempting to address this with writing a custom load-balancer and subchannel logic seems like an overkill for such library.

In comparison, RestTransport ends up being massively faster for big upsert/fetch/delete operations as it sidesteps the issue by using http 1.1 still, at least it does not upgrade with more or less default HttpClient configuration. Interestingly enough, as of .NET 9 RC.1, using RestTransport with NativeAOT ends up consuming less memory at load spike and idle, and of course there are binary size savings too since it reuses the same System.Text.Json code for both the control and data planes. It might be a good idea to use the 3. break opportunity to make it a default. Might be worth asking Pinecone about their http/2 issue too as it reproduces with rest client as well, if you set version 2 and connection policy as version requested or above.

@neon-sunset neon-sunset merged commit d462352 into neon-sunset:main Sep 18, 2024
1 check failed
@neon-sunset
Copy link
Owner

neon-sunset commented Sep 27, 2024

@maumar The version 3.0.0 which includes this change has been released: https://github.com/neon-sunset/Pinecone.NET/releases
This release also switches to ReadOnlyMemory<float> to stop forcing Semantic Kernel to allocate large arrays whenever constructing vectors for Pinecone. The mapping in SK needs to be updated to account for this, however. The new default transport choice is Rest and if you would like to know why - I have added notes that explain the motivation to README: https://github.com/neon-sunset/Pinecone.NET?tab=readme-ov-file#rest-vs-grpc-transport

Thank you!

Update: I have looked at how connectors are implemented in Semantic Kernel and am drinking vodka.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Consider integrating ILogger into PineconeClient and ITransport<T> implementations
2 participants