nirikshaai 0.0.1.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,563 @@
1
+ Metadata-Version: 2.4
2
+ Name: nirikshaai
3
+ Version: 0.0.1.dev1
4
+ Summary: NirikshaAI Python SDK — full-stack observability via OpenTelemetry
5
+ License: Apache-2.0
6
+ Keywords: observability,opentelemetry,tracing,metrics,logs,apm
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: Apache Software License
10
+ Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: opentelemetry-sdk>=1.24
13
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.24
14
+ Provides-Extra: all
15
+ Requires-Dist: opentelemetry-instrumentation-django>=0.45b0; extra == "all"
16
+ Requires-Dist: opentelemetry-instrumentation-flask>=0.45b0; extra == "all"
17
+ Requires-Dist: opentelemetry-instrumentation-fastapi>=0.45b0; extra == "all"
18
+ Requires-Dist: opentelemetry-instrumentation-starlette>=0.45b0; extra == "all"
19
+ Requires-Dist: opentelemetry-instrumentation-requests>=0.45b0; extra == "all"
20
+ Requires-Dist: opentelemetry-instrumentation-urllib3>=0.45b0; extra == "all"
21
+ Requires-Dist: opentelemetry-instrumentation-aiohttp-client>=0.45b0; extra == "all"
22
+ Requires-Dist: opentelemetry-instrumentation-grpc>=0.45b0; extra == "all"
23
+ Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.45b0; extra == "all"
24
+ Requires-Dist: opentelemetry-instrumentation-psycopg2>=0.45b0; extra == "all"
25
+ Requires-Dist: opentelemetry-instrumentation-pymongo>=0.45b0; extra == "all"
26
+ Requires-Dist: opentelemetry-instrumentation-redis>=0.45b0; extra == "all"
27
+ Requires-Dist: opentelemetry-instrumentation-celery>=0.45b0; extra == "all"
28
+ Provides-Extra: llm
29
+ Requires-Dist: opentelemetry-instrumentation-openai>=0.27b0; extra == "llm"
30
+ Requires-Dist: opentelemetry-instrumentation-anthropic>=0.27b0; extra == "llm"
31
+ Requires-Dist: opentelemetry-instrumentation-langchain>=0.27b0; extra == "llm"
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=8.0; extra == "dev"
34
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
35
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
36
+ Requires-Dist: ruff>=0.4.0; extra == "dev"
37
+ Requires-Dist: mypy>=1.10; extra == "dev"
38
+ Requires-Dist: coverage[toml]>=7.5; extra == "dev"
39
+
40
+ # NirikshaAI Python SDK
41
+
42
+ [![CI](https://github.com/san-data-systems/niriksha-sdk-python/actions/workflows/ci.yml/badge.svg)](https://github.com/san-data-systems/niriksha-sdk-python/actions/workflows/ci.yml)
43
+ [![PyPI version](https://img.shields.io/pypi/v/nirikshaai.svg)](https://pypi.org/project/nirikshaai/)
44
+ [![Python versions](https://img.shields.io/pypi/pyversions/nirikshaai.svg)](https://pypi.org/project/nirikshaai/)
45
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
46
+
47
+ The official Python SDK for [NirikshaAI](https://nirikshaai.com) — AI-native observability for logs, metrics, traces, and LLM/agent telemetry.
48
+
49
+ Under the hood this is a thin wrapper around the [OpenTelemetry Python SDK](https://opentelemetry.io/docs/languages/python/). It configures OTLP exporters, wires up auto-instrumentation, and exposes NirikshaAI-specific helpers (evals, prompt management). You can use the standard OTEL API at any time alongside it.
50
+
51
+ ---
52
+
53
+ ## Table of Contents
54
+
55
+ - [Installation](#installation)
56
+ - [Quick Start](#quick-start)
57
+ - [LLM Applications](#llm-applications)
58
+ - [Configuration Reference](#configuration-reference)
59
+ - [Auto-Instrumented Libraries](#auto-instrumented-libraries)
60
+ - [Using the Standard OTEL API](#using-the-standard-otel-api)
61
+ - [Logging Integration](#logging-integration)
62
+ - [Eval Submission](#eval-submission)
63
+ - [Prompt Management](#prompt-management)
64
+ - [Framework Examples](#framework-examples)
65
+ - [Environment Variables](#environment-variables)
66
+
67
+ ---
68
+
69
+ ## Installation
70
+
71
+ ```bash
72
+ pip install nirikshaai
73
+ ```
74
+
75
+ To include automatic instrumentation for common web frameworks and infrastructure libraries (Django, Flask, FastAPI, SQLAlchemy, Redis, etc.):
76
+
77
+ ```bash
78
+ pip install "nirikshaai[all]"
79
+ ```
80
+
81
+ To also include automatic instrumentation for LLM libraries (OpenAI, Anthropic, LangChain, etc.):
82
+
83
+ ```bash
84
+ pip install "nirikshaai[all,llm]"
85
+ ```
86
+
87
+ **Minimum Python version:** 3.9
88
+
89
+ ---
90
+
91
+ ## Quick Start
92
+
93
+ Two lines is all it takes to start sending traces, metrics, and logs to NirikshaAI from any Python service:
94
+
95
+ ```python
96
+ import nirikshaai
97
+
98
+ nirikshaai.init(
99
+ endpoint="https://app.niriksha.ai",
100
+ otlp_endpoint="grpc-ingest.niriksha.ai:443", # SaaS: OTLP gateway is separate from the REST API
101
+ api_key="nai_...",
102
+ service_name="my-service",
103
+ )
104
+ # That's it — traces, metrics, and logs now flow to NirikshaAI
105
+ ```
106
+
107
+ Your `api_key` is a project-scoped key (prefixed `nai_`). It encodes which org and project your telemetry belongs to — you do not need to pass org or project IDs separately.
108
+
109
+ ---
110
+
111
+ ## LLM Applications
112
+
113
+ Enable LLM instrumentation with the `enable_llm` flag. When set, the SDK automatically patches supported LLM client libraries so that every API call creates a standard OpenTelemetry span with token counts, model name, and (optionally) prompt/completion content.
114
+
115
+ ```python
116
+ import nirikshaai
117
+
118
+ nirikshaai.init(
119
+ endpoint="https://app.niriksha.ai",
120
+ api_key="nai_...",
121
+ service_name="my-ai-service",
122
+ enable_llm=True, # Auto-instruments OpenAI, Anthropic, LangChain, etc.
123
+ capture_prompts=False, # Set True only if PII controls are in place
124
+ )
125
+
126
+ import openai # auto-instrumented — every call creates an OTEL span
127
+
128
+ client = openai.OpenAI()
129
+ response = client.chat.completions.create(
130
+ model="gpt-4o",
131
+ messages=[{"role": "user", "content": "Summarise this document."}],
132
+ )
133
+ # A LLM span is emitted automatically — no extra code needed
134
+ ```
135
+
136
+ > **Privacy note:** `capture_prompts=False` is the default. Setting it to `True` will capture the full text of prompts and completions as span attributes (`llm.input.messages` / `llm.output.messages`). Only enable this if you have appropriate data governance and PII controls in place.
137
+
138
+ ---
139
+
140
+ ## Configuration Reference
141
+
142
+ All parameters are passed to `nirikshaai.init()`.
143
+
144
+ | Parameter | Type | Default | Description |
145
+ |---|---|---|---|
146
+ | `endpoint` | `str` | *(required)* | NirikshaAI REST/control-plane base URL. SaaS: `https://app.niriksha.ai`. Private Cloud: `https://niriksha.internal` |
147
+ | `api_key` | `str` | *(required)* | Project-scoped API key with `nai_` prefix |
148
+ | `service_name` | `str` | `"my-service"` | Value of the `service.name` OTEL resource attribute |
149
+ | `environment` | `str` | `"production"` | Value of the `deployment.environment` OTEL resource attribute |
150
+ | `enable_metrics` | `bool` | `True` | Export OTLP metrics on a 60-second periodic interval |
151
+ | `enable_logs` | `bool` | `True` | Attach an OTLP log handler to the root Python `logging` logger |
152
+ | `enable_llm` | `bool` | `False` | Auto-instrument supported LLM client libraries (opt-in) |
153
+ | `capture_prompts` | `bool` | `False` | Capture `llm.input/output.messages` span attributes (PII risk) |
154
+ | `otlp_port` | `int` | `4317` | OTLP gRPC port. Ignored when `otlp_endpoint` is set. |
155
+ | `otlp_endpoint` | `str` | `None` | Override the gRPC OTLP address (`host:port`, no scheme). SaaS: `grpc-ingest.niriksha.ai:443` |
156
+ | `insecure` | `bool` | `False` | Send gRPC without TLS. Use when TLS is terminated at an ingress. |
157
+ | `tls_skip_verify` | `bool` | `False` | Use TLS but skip server certificate validation. Dev/staging only. |
158
+ | `ca_cert_file` | `str` | `None` | Path to a PEM CA certificate for verifying the gateway TLS cert. |
159
+ | `disable_instrumentations` | `list[str]` | `[]` | Library names to skip during auto-instrumentation (e.g. `["django"]`) |
160
+
161
+ ### Private Cloud examples
162
+
163
+ ```python
164
+ # TLS with trusted certificate (system roots)
165
+ nirikshaai.init(
166
+ endpoint="https://niriksha.internal",
167
+ otlp_endpoint="niriksha.internal:4317",
168
+ api_key="nai_...",
169
+ )
170
+
171
+ # Custom / self-signed CA
172
+ nirikshaai.init(
173
+ endpoint="https://niriksha.internal",
174
+ otlp_endpoint="niriksha.internal:4317",
175
+ api_key="nai_...",
176
+ ca_cert_file="/etc/ssl/niriksha-ca.crt",
177
+ )
178
+
179
+ # Skip TLS verification (dev/staging only)
180
+ nirikshaai.init(
181
+ endpoint="https://niriksha.internal",
182
+ otlp_endpoint="niriksha.internal:4317",
183
+ api_key="nai_...",
184
+ tls_skip_verify=True,
185
+ )
186
+
187
+ # Plaintext gRPC (TLS terminated at ingress)
188
+ nirikshaai.init(
189
+ endpoint="https://niriksha.internal",
190
+ otlp_endpoint="niriksha.internal:4317",
191
+ api_key="nai_...",
192
+ insecure=True,
193
+ )
194
+ ```
195
+
196
+ ---
197
+
198
+ ## Auto-Instrumented Libraries
199
+
200
+ ### General (always enabled when the package is installed)
201
+
202
+ | Library | What's captured |
203
+ |---|---|
204
+ | `django` | HTTP requests and responses, middleware timing, view names |
205
+ | `flask` | Routes, request timing, status codes |
206
+ | `fastapi` | Routes, request timing, async support, response codes |
207
+ | `starlette` | Routes, middleware, ASGI lifecycle |
208
+ | `requests` | Outbound HTTP calls, method, URL, status code |
209
+ | `urllib3` | Low-level HTTP connections and retries |
210
+ | `aiohttp` | Async HTTP client calls |
211
+ | `grpc` | gRPC server and client calls, method names |
212
+ | `sqlalchemy` | SQL queries and transaction timing (values are not captured) |
213
+ | `psycopg2` | PostgreSQL query timing and operation type |
214
+ | `asyncpg` | Async PostgreSQL query timing |
215
+ | `pymongo` | MongoDB operation type, collection, database |
216
+ | `redis` | Redis command name (values are not captured) |
217
+ | `celery` | Task name, queue, execution state, retry count |
218
+
219
+ ### LLM (requires `enable_llm=True`)
220
+
221
+ | Library | What's captured |
222
+ |---|---|
223
+ | `openai` | Chat completions, embeddings, model name, token usage (prompt + completion) |
224
+ | `anthropic` | Messages API calls, model name, token usage |
225
+ | `langchain` | Chain invocations, individual tool call spans, retrieval steps |
226
+ | `llama_index` | Query engine spans, retrieval spans, synthesiser spans |
227
+ | `mistralai` | Chat completions, model name, token usage |
228
+ | `google-generativeai` | Gemini API calls, model name, token usage |
229
+
230
+ ---
231
+
232
+ ## Using the Standard OTEL API
233
+
234
+ `nirikshaai.init()` configures the global OpenTelemetry providers. You can use the standard OTEL API directly at any point after calling `init()`:
235
+
236
+ ```python
237
+ from opentelemetry import trace, metrics
238
+
239
+ tracer = trace.get_tracer("my-service")
240
+ meter = metrics.get_meter("my-service")
241
+
242
+ # Custom span
243
+ with tracer.start_as_current_span("process-order") as span:
244
+ span.set_attribute("order.id", order_id)
245
+ span.set_attribute("order.total", total)
246
+ span.set_attribute("order.currency", "USD")
247
+ result = fulfil_order(order_id)
248
+ span.set_attribute("order.status", result.status)
249
+
250
+ # Custom counter
251
+ order_counter = meter.create_counter(
252
+ "orders.processed",
253
+ description="Number of orders processed",
254
+ unit="{order}",
255
+ )
256
+ order_counter.add(1, {"status": "success", "region": "us-east"})
257
+
258
+ # Custom histogram (useful for latency)
259
+ latency_histogram = meter.create_histogram(
260
+ "order.processing.duration",
261
+ description="Time to process an order",
262
+ unit="ms",
263
+ )
264
+ latency_histogram.record(142.5, {"order_type": "express"})
265
+ ```
266
+
267
+ ---
268
+
269
+ ## Logging Integration
270
+
271
+ When `enable_logs=True` (the default), the SDK attaches an OTLP log handler to Python's root logger. All log records emitted through the standard `logging` module are automatically exported to NirikshaAI, with trace and span IDs attached so log lines are correlated to their parent trace.
272
+
273
+ ```python
274
+ import logging
275
+
276
+ logger = logging.getLogger("my-service")
277
+
278
+ # Structured extra fields are forwarded as log record attributes
279
+ logger.info("Order processed", extra={"order_id": "abc123", "amount": 99.99})
280
+ logger.warning("Inventory low", extra={"sku": "WIDGET-001", "remaining": 3})
281
+ logger.error("Payment failed", extra={"error_code": "CARD_DECLINED", "order_id": "abc123"})
282
+
283
+ # Exception info is captured automatically
284
+ try:
285
+ process_payment(order)
286
+ except PaymentError as exc:
287
+ logger.exception("Unhandled payment error", extra={"order_id": order.id})
288
+ ```
289
+
290
+ Logs are exported in batches over OTLP gRPC to the same endpoint as traces and metrics.
291
+
292
+ ---
293
+
294
+ ## Eval Submission
295
+
296
+ Submit evaluation results for LLM responses. Evals are linked to a specific trace so results appear in the NirikshaAI LLM Traces view alongside the originating span.
297
+
298
+ ### Single eval
299
+
300
+ ```python
301
+ import nirikshaai
302
+
303
+ nirikshaai.submit_eval(
304
+ trace_id="your-otel-trace-id", # hex trace ID from the OTEL span context
305
+ metric_name="faithfulness",
306
+ score=0.92, # float in [0, 1]
307
+ label="pass", # "pass" | "fail" | any custom label
308
+ explanation="Response accurately reflects the source documents",
309
+ eval_type="llm_judge", # "llm_judge" | "rule_based" | "human"
310
+ )
311
+ ```
312
+
313
+ ### Batch eval
314
+
315
+ ```python
316
+ nirikshaai.submit_evals_batch([
317
+ {
318
+ "trace_id": "abc123...",
319
+ "metric_name": "toxicity",
320
+ "score": 0.02,
321
+ "label": "pass",
322
+ "eval_type": "rule_based",
323
+ },
324
+ {
325
+ "trace_id": "abc123...",
326
+ "metric_name": "relevance",
327
+ "score": 0.87,
328
+ "label": "pass",
329
+ "eval_type": "llm_judge",
330
+ "explanation": "Response addresses the user's question directly",
331
+ },
332
+ ])
333
+ ```
334
+
335
+ ### Obtaining the trace ID from an active span
336
+
337
+ ```python
338
+ from opentelemetry import trace
339
+
340
+ with tracer.start_as_current_span("llm-call") as span:
341
+ ctx = span.get_span_context()
342
+ trace_id = format(ctx.trace_id, "032x") # 32-character hex string
343
+
344
+ response = client.chat.completions.create(...)
345
+
346
+ # Submit eval referencing this trace
347
+ nirikshaai.submit_eval(
348
+ trace_id=trace_id,
349
+ metric_name="faithfulness",
350
+ score=judge(response),
351
+ label="pass",
352
+ )
353
+ ```
354
+
355
+ ---
356
+
357
+ ## Prompt Management
358
+
359
+ Fetch versioned prompt templates from the NirikshaAI prompt vault. Variable substitution is performed server-side before the rendered text is returned.
360
+
361
+ ### Fetch the latest deployed version
362
+
363
+ ```python
364
+ prompt = nirikshaai.get_prompt("customer-support-system")
365
+ print(prompt["text"]) # Rendered prompt text
366
+ print(prompt["version"]) # Active version number
367
+ print(prompt["name"])
368
+ ```
369
+
370
+ ### Fetch a specific version with variable substitution
371
+
372
+ ```python
373
+ prompt = nirikshaai.get_prompt(
374
+ "product-description",
375
+ version=3,
376
+ variables={
377
+ "product_name": "Widget Pro",
378
+ "category": "Electronics",
379
+ "price": "$49.99",
380
+ },
381
+ )
382
+ print(prompt["text"]) # All {{variables}} replaced server-side
383
+ ```
384
+
385
+ ### List all available prompts
386
+
387
+ ```python
388
+ prompts = nirikshaai.list_prompts()
389
+ for p in prompts:
390
+ print(f"{p['name']} (v{p['version']}) — {p['description']}")
391
+ ```
392
+
393
+ ---
394
+
395
+ ## Framework Examples
396
+
397
+ ### Django
398
+
399
+ Call `nirikshaai.init()` in your `settings.py` (or in an `AppConfig.ready()` method). Auto-instrumentation is applied globally once at startup.
400
+
401
+ ```python
402
+ # myproject/settings.py
403
+ import nirikshaai
404
+
405
+ nirikshaai.init(
406
+ endpoint="https://app.niriksha.ai",
407
+ api_key="nai_...",
408
+ service_name="django-app",
409
+ environment="production",
410
+ )
411
+
412
+ INSTALLED_APPS = [
413
+ # ... your apps
414
+ ]
415
+ ```
416
+
417
+ ### Flask
418
+
419
+ ```python
420
+ from flask import Flask
421
+ import nirikshaai
422
+
423
+ # init() before creating the Flask app
424
+ nirikshaai.init(
425
+ endpoint="https://app.niriksha.ai",
426
+ api_key="nai_...",
427
+ service_name="flask-app",
428
+ )
429
+
430
+ app = Flask(__name__)
431
+
432
+ @app.route("/orders/<order_id>")
433
+ def get_order(order_id):
434
+ # This route is automatically traced — no extra code needed
435
+ order = db.get_order(order_id)
436
+ return {"id": order_id, "status": order.status}
437
+ ```
438
+
439
+ ### FastAPI
440
+
441
+ ```python
442
+ from fastapi import FastAPI
443
+ import nirikshaai
444
+
445
+ nirikshaai.init(
446
+ endpoint="https://app.niriksha.ai",
447
+ api_key="nai_...",
448
+ service_name="fastapi-app",
449
+ )
450
+
451
+ app = FastAPI()
452
+
453
+ @app.get("/orders/{order_id}")
454
+ async def get_order(order_id: str):
455
+ # Async routes are fully supported — traced automatically
456
+ order = await db.get_order(order_id)
457
+ return {"id": order_id, "status": order.status}
458
+ ```
459
+
460
+ ### Celery
461
+
462
+ ```python
463
+ from celery import Celery
464
+ import nirikshaai
465
+
466
+ nirikshaai.init(
467
+ endpoint="https://app.niriksha.ai",
468
+ api_key="nai_...",
469
+ service_name="celery-worker",
470
+ )
471
+
472
+ app = Celery("tasks", broker="redis://localhost:6379/0")
473
+
474
+ @app.task
475
+ def send_notification(user_id: str, message: str):
476
+ # Every task invocation is automatically traced
477
+ # The task name, queue, and retry count appear as span attributes
478
+ notify(user_id, message)
479
+ ```
480
+
481
+ ### LLM application with eval feedback loop
482
+
483
+ ```python
484
+ import nirikshaai
485
+ from opentelemetry import trace
486
+
487
+ nirikshaai.init(
488
+ endpoint="https://app.niriksha.ai",
489
+ api_key="nai_...",
490
+ service_name="rag-service",
491
+ enable_llm=True,
492
+ )
493
+
494
+ import openai
495
+
496
+ client = openai.OpenAI()
497
+ tracer = trace.get_tracer("rag-service")
498
+
499
+ def answer_question(question: str) -> str:
500
+ with tracer.start_as_current_span("answer-question") as span:
501
+ span.set_attribute("question.length", len(question))
502
+
503
+ # LLM call is auto-instrumented — a child span is created
504
+ response = client.chat.completions.create(
505
+ model="gpt-4o",
506
+ messages=[
507
+ {"role": "system", "content": "You are a helpful assistant."},
508
+ {"role": "user", "content": question},
509
+ ],
510
+ )
511
+ answer = response.choices[0].message.content
512
+
513
+ # Record trace ID for eval submission
514
+ ctx = span.get_span_context()
515
+ trace_id = format(ctx.trace_id, "032x")
516
+
517
+ # Async eval — run your judge independently and post the result
518
+ score = run_faithfulness_judge(question, answer)
519
+ nirikshaai.submit_eval(
520
+ trace_id=trace_id,
521
+ metric_name="faithfulness",
522
+ score=score,
523
+ label="pass" if score >= 0.8 else "fail",
524
+ eval_type="llm_judge",
525
+ )
526
+
527
+ return answer
528
+ ```
529
+
530
+ ---
531
+
532
+ ## Environment Variables
533
+
534
+ You can configure the SDK through standard OpenTelemetry environment variables instead of (or in addition to) passing arguments to `init()`. Environment variables take lower precedence than explicit arguments.
535
+
536
+ | Variable | Equivalent `init()` parameter |
537
+ |---|---|
538
+ | `OTEL_SERVICE_NAME` | `service_name` |
539
+ | `OTEL_EXPORTER_OTLP_ENDPOINT` | Derived from `endpoint` + `otlp_port` |
540
+ | `OTEL_EXPORTER_OTLP_HEADERS` | Set to `X-API-Key=nai_your_key` |
541
+ | `OTEL_RESOURCE_ATTRIBUTES` | Use to set `deployment.environment` and other attributes |
542
+
543
+ Example shell setup:
544
+
545
+ ```bash
546
+ export OTEL_SERVICE_NAME=my-service
547
+ export OTEL_EXPORTER_OTLP_ENDPOINT=http://your-nirikshaai:4317
548
+ export OTEL_EXPORTER_OTLP_HEADERS="X-API-Key=nai_your_key"
549
+ export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=production"
550
+ ```
551
+
552
+ Then call `init()` with no arguments (the SDK will read the environment):
553
+
554
+ ```python
555
+ import nirikshaai
556
+ nirikshaai.init()
557
+ ```
558
+
559
+ ---
560
+
561
+ ## License
562
+
563
+ Apache 2.0 — see [LICENSE](LICENSE).