ITADN

Add instrumentation for asyncua (OPC UA client)

#4491Openluke6Lh43 创建于 2026-04-27
feature-request
L
luke6Lh43commented
### What problem do you want to solve? Python applications communicating with industrial control systems (PLCs, SCADA, MES) via OPC UA currently have no first-class OpenTelemetry instrumentation. The most popular Python OPC UA library, [`asyncua`](https://github.com/FreeOpcUa/opcua-asyncio) (1.4k GitHub stars, actively maintained, used in industrial IoT gateways, MES integrations, and data historian pipelines), has no instrumentor in `opentelemetry-python-contrib`. Client-side Python instrumentation for `asyncua` would enable observability for Python-based industrial integrations. ### Describe the solution you'd like A new package `opentelemetry-instrumentation-asyncua` in `opentelemetry-python-contrib`, extending `BaseInstrumentor` and following the established patterns in this repo (structurally modeled on `asyncpg`, `redis`, and similar). ### MVP scope (initial PR) Traces for client-initiated OPC UA operations: - `Client.connect` → `opcua.connect` span - `Client.disconnect` → `opcua.disconnect` span - `Node.read_value` → `opcua.read` span - `Node.write_value` → `opcua.write` span - `Node.call_method` → `opcua.call_method` span All spans are `SpanKind.CLIENT`. Attributes include: - `opcua.operation` (read / write / connect / etc.) - `opcua.endpoint`, `server.address`, `server.port` (target identification) - `opcua.node_id` (canonical OPC UA form via `NodeId.to_string()`) - `opcua.security_policy`, `opcua.security_mode` (security posture) - `opcua.method_id`, `opcua.method_args_count` (for method calls) - `opcua.variant_type` (for writes) - `error.type` and span status on exceptions asyncua's `Node` class is shared between client and server code paths, so wrappers filter out server-internal operations (e.g., address space setup reads/writes) by inspecting the node's session type — ensuring only genuine client-initiated calls produce spans. ### Deferred to follow-up work - Subscriptions and monitored items (design question: data change notifications are long-lived server-push via client-initiated polling; likely modeled as `CONSUMER` spans with links to the subscription span, similar to existing messaging conventions) - Browse / address space navigation - Metrics (operation duration histogram, active subscriptions gauge) - OPC UA `StatusCode` extraction from response `DataValue` (would require wrapping lower-level methods where the full response is visible) - OPC UA-specific semantic conventions proposal (separate work in `semantic-conventions`) ### Questions for maintainers Before opening a PR, I'd appreciate guidance on three points: 1. **Semantic conventions approach**: There are no stable OTel semantic conventions for OPC UA yet. Would you prefer: - (a) A provisional `opcua.*` attribute namespace, documented as experimental, with parallel work to propose stable conventions in `semantic-conventions`? - (b) Generic `rpc.*` conventions with `rpc.system = "opcua"`? - (c) Something else? My current prototype uses (a). Happy to change direction. 2. **Scope of MVP**: Is the scope above acceptable for an initial PR, or would you expect subscriptions to be covered in the first drop? Subscriptions add design complexity (long-lived notifications, span/metric split) that I'd prefer to address in a focused follow-up. 3. **Package naming**: I'm proposing `opentelemetry-instrumentation-asyncua` (library-specific, following the `pymysql`/`mysql`/`mysqlclient` precedent) rather than `opentelemetry-instrumentation-opcua` (protocol-specific). Does that work? ### Describe alternatives you've considered - **Manual instrumentation with the OTel SDK** — works but requires every user to reimplement. A standard instrumentation in this repo is more valuable for the ecosystem. - **Third-party PyPI package outside contrib** — would fragment the ecosystem and reduce discoverability. Hosting in `opentelemetry-python-contrib` signals community ownership and ensures maintenance continuity alongside the rest of the instrumentation catalog. - **Waiting for stable OPC UA semantic conventions before implementing** — this could take a long time and leaves Python users without a standard instrumentation indefinitely. A provisional `opcua.*` namespace now, adjusted later to match stabilized conventions, seems more pragmatic. ### Additional Context I have a working local prototype implementing the MVP scope described above. It passes lint (ruff) and produces clean, verified spans end-to-end against a local asyncua server: ```console Span: opcua.connect (kind=CLIENT, duration=3.46 ms) opcua.operation = connect opcua.endpoint = opc.tcp://localhost:14840/test/ server.address = localhost server.port = 14840 opcua.security_policy = None opcua.security_mode = None Span: opcua.read (kind=CLIENT, duration=0.54 ms) opcua.operation = read opcua.node_id = ns=2;i=2 Span: opcua.write (kind=CLIENT, duration=0.36 ms) opcua.operation = write opcua.node_id = ns=2;i=2 Span: opcua.disconnect (kind=CLIENT, duration=0.52 ms) opcua.operation = disconnect opcua.endpoint = opc.tcp://localhost:14840/test/ ``` ### Would you like to implement a fix? Yes ### Tip <sub>[React](https://github.blog/news-insights/product-news/add-reactions-to-pull-requests-issues-and-comments/) with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding `+1` or `me too`, to help us triage it. Learn more [here](https://opentelemetry.io/community/end-user/issue-participation/).</sub>
0 条评论