-
Notifications
You must be signed in to change notification settings - Fork 41
Add diagnostics / logging package with full logger coverage #163
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
Merged
rhurey
merged 6 commits into
microsoft:master
from
mohamed-zaki-coding:feature/diagnostics-logging-only
Mar 4, 2026
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
145a065
Add diagnostics/logging package with full logger coverage
mohamed-zaki-coding 4d91ba8
Update README with diagnostics/logging docs and modernize links
mohamed-zaki-coding f60a504
Update diagnostics README with usage examples, test inventory, file l…
mohamed-zaki-coding a7a858e
Revert root README to upstream original
mohamed-zaki-coding 9e08a11
Remove redundant code: delegate deprecated API, deduplicate helpers, …
mohamed-zaki-coding 34a19d8
Merge branch 'master' into feature/diagnostics-logging-only
rhurey File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| # Go Diagnostics Binding Architecture | ||
|
|
||
| This document describes the architecture used for the Go Diagnostics API in Speech SDK bindings. | ||
|
|
||
| ## Goals | ||
|
|
||
| - Provide feature parity with Java/Python/C# diagnostics surfaces. | ||
| - Keep Go API idiomatic while preserving native SDK behavior. | ||
| - Isolate CGo/native interop details behind small, focused abstractions. | ||
| - Maintain backward compatibility for existing users of the legacy `diagnostics` package. | ||
|
|
||
| ## Package Layout | ||
|
|
||
| ### `diagnostics/logging` (new primary API) | ||
|
|
||
| This package contains the full diagnostics surface: | ||
|
|
||
| - `FileLogger` for file logging | ||
| - `MemoryLogger` for memory-ring logging and dump helpers | ||
| - `EventLogger` for callback-based log streaming | ||
| - `ConsoleLogger` for stdout/stderr logging | ||
| - `TraceError`, `TraceWarning`, `TraceInfo`, `TraceVerbose` (+ `WithCaller` variants) | ||
| - `Level` enum-like type (`Error`, `Warning`, `Info`, `Verbose`) | ||
|
|
||
| Files are intentionally split by logger/type to keep ownership and review scope small. | ||
|
|
||
| ### `diagnostics` (deprecated compatibility layer) | ||
|
|
||
| This package keeps old entry points available and forwards behavior to equivalent native diagnostics APIs. | ||
|
|
||
| - Marked with `Deprecated:` comments. | ||
| - Intended only for compatibility during migration. | ||
| - New work should target `diagnostics/logging`. | ||
|
|
||
| ## Architectural Decisions | ||
|
|
||
| ### 1) Singleton logger model | ||
|
|
||
| Each logger is a package-level singleton (`FileLogger`, `MemoryLogger`, etc.) matching the native SDK's process-wide semantics and the shape used in other language bindings. | ||
|
|
||
| ### 2) Thin wrappers around native C APIs | ||
|
|
||
| Go methods map ~1:1 to native diagnostics APIs from `speechapi_c_diagnostics.h`, keeping behavior changes centralized in the native layer. | ||
|
|
||
| ### 3) Explicit CGo boundary ownership | ||
|
|
||
| All callback bridge code lives in `logging/cfunctions.go`: C trampoline -> exported Go function -> mutex-guarded dispatch. This avoids glue duplication and keeps thread-safety constraints visible. | ||
|
|
||
| ### 4) Property bag for file logger configuration | ||
|
|
||
| `FileLogger.Start` passes `SPEECH-LogFilename` and `SPEECH-AppendToLogFile` via a temporary property bag, mirroring the native/C++/Java pattern. | ||
|
|
||
| ### 5) Backward compatibility strategy | ||
|
|
||
| Legacy `diagnostics` package stays available with `Deprecated:` markers guiding users to `diagnostics/logging`. | ||
|
|
||
| ## Error Handling | ||
|
|
||
| - Native result codes (`SPXHR`/`AZACHR`) surface as Go `error` values via lightweight wrappers. | ||
| - Native `void` APIs remain fire-and-forget. Invalid caller input is validated early where useful. | ||
|
|
||
| ## Concurrency | ||
|
|
||
| - Native event callbacks arrive on SDK worker threads. | ||
| - `EventLogger` protects state with a mutex; callback handlers should be fast and non-blocking. | ||
|
|
||
| ## Quick Start | ||
|
|
||
| ```go | ||
| import "github.com/Microsoft/cognitive-services-speech-sdk-go/diagnostics/logging" | ||
|
|
||
| // File logging | ||
| logging.FileLogger.Start("/tmp/speech.log") | ||
| defer logging.FileLogger.Stop() | ||
|
|
||
| // Memory logging with dump | ||
| logging.MemoryLogger.Start() | ||
| defer logging.MemoryLogger.Stop() | ||
| logging.TraceInfo("recognized: %s", result.Text) | ||
| lines := logging.MemoryLogger.DumpToSlice() | ||
|
|
||
| // Event-based logging | ||
| logging.EventLogger.SetCallback(func(msg string) { | ||
| fmt.Println(msg) | ||
| }) | ||
| defer logging.EventLogger.SetCallback(nil) | ||
|
|
||
| // Console logging | ||
| logging.ConsoleLogger.Start() | ||
| defer logging.ConsoleLogger.Stop() | ||
|
|
||
| // Set log level | ||
| logging.FileLogger.SetLevel(logging.Error) | ||
| ``` | ||
|
|
||
| ## Testing | ||
|
|
||
| Integration tests are gated by `SPEECH_SDK_AVAILABLE=1`; pure unit tests (e.g. `TestLevelString`, `TestLoggingError`) run unconditionally. | ||
|
|
||
| ## Local Validation | ||
|
|
||
| Requirements: Go toolchain, CGo-compatible C compiler, Speech SDK headers and native library. | ||
|
|
||
| Key environment variables: `CGO_ENABLED=1`, `CGO_CFLAGS` (header path), `CGO_LDFLAGS` (lib path), `SPEECH_SDK_AVAILABLE=1`. | ||
|
|
||
| Run tests via CMake: | ||
|
|
||
| ```bash | ||
| cmake --build build --target go-tests --config Release | ||
| cmake --build build --target go-tests-race --config Release | ||
| ``` | ||
|
|
||
| ## Extension Guidelines | ||
|
|
||
| 1. Add new capabilities in `diagnostics/logging` first. | ||
| 2. Keep Go naming idiomatic but parity-aligned with Java/Python/C#. | ||
| 3. Mirror native signatures closely; add tests for success and error paths. | ||
| 4. Only add compatibility shims in `diagnostics` when needed for non-breaking upgrades. | ||
|
|
||
| ## Known Constraints | ||
|
|
||
| - Logging is process-wide by native SDK design. | ||
| - Event callback is a single registration point per process. | ||
| - Integration tests are opt-in via `SPEECH_SDK_AVAILABLE=1`. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| // Copyright (c) Microsoft. All rights reserved. | ||
| // Licensed under the MIT license. See LICENSE.md file in the project root for full license information. | ||
|
|
||
| package diagnostics | ||
|
|
||
| import ( | ||
| "os" | ||
| "path/filepath" | ||
| "testing" | ||
| ) | ||
|
|
||
| func skipIfNoSDK(t *testing.T) { | ||
| t.Helper() | ||
| if os.Getenv("SPEECH_SDK_AVAILABLE") != "1" { | ||
| t.Skip("Skipping integration test: SPEECH_SDK_AVAILABLE not set") | ||
| } | ||
| } | ||
|
|
||
| func TestStartStopFileLogging(t *testing.T) { | ||
| skipIfNoSDK(t) | ||
|
|
||
| logPath := filepath.Join(t.TempDir(), "legacy_diagnostics.log") | ||
| if err := StartFileLogging(logPath); err != nil { | ||
| t.Fatalf("StartFileLogging: %v", err) | ||
| } | ||
| if err := StopFileLogging(); err != nil { | ||
| t.Fatalf("StopFileLogging: %v", err) | ||
| } | ||
| } | ||
|
|
||
| func TestStartStopFileLoggingAppendMode(t *testing.T) { | ||
| skipIfNoSDK(t) | ||
|
|
||
| logPath := filepath.Join(t.TempDir(), "legacy_diagnostics_append.log") | ||
| if err := StartFileLogging(logPath, true); err != nil { | ||
| t.Fatalf("StartFileLogging(append): %v", err) | ||
| } | ||
| if err := StopFileLogging(); err != nil { | ||
| t.Fatalf("StopFileLogging: %v", err) | ||
| } | ||
| } | ||
|
|
||
| func TestStartConsoleLoggingDefault(t *testing.T) { | ||
| skipIfNoSDK(t) | ||
|
|
||
| StartConsoleLogging() | ||
| StopConsoleLogging() | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,23 +1,30 @@ | ||
| // Copyright (c) Microsoft. All rights reserved. | ||
| // Licensed under the MIT license. See LICENSE.md file in the project root for full license information. | ||
|
|
||
| package diagnostics | ||
|
|
||
| // #include <azac_error.h> | ||
| // #include <azac_api_c_common.h> | ||
| // | ||
| // static const char* diagnostics_get_error_message(uintptr_t code) { | ||
| // return error_get_message((AZAC_HANDLE)code); | ||
| // } | ||
| import "C" | ||
|
|
||
| import "fmt" | ||
|
|
||
| type diagnosticsError struct { | ||
| operation string | ||
| code uintptr | ||
| operation string | ||
| code uintptr | ||
| } | ||
|
|
||
| func newDiagnosticsError(operation string, code uintptr) error { | ||
| return &diagnosticsError{ | ||
| operation: operation, | ||
| code: code, | ||
| } | ||
| return &diagnosticsError{ | ||
| operation: operation, | ||
| code: code, | ||
| } | ||
| } | ||
|
|
||
| func (e *diagnosticsError) Error() string { | ||
| return fmt.Sprintf("diagnostics operation '%s' failed with error code %d", e.operation, e.code) | ||
| msg := C.GoString(C.diagnostics_get_error_message(C.uintptr_t(e.code))) | ||
| return fmt.Sprintf("diagnostics operation '%s' failed with error code 0x%x (%s)", e.operation, e.code, msg) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| // Copyright (c) Microsoft. All rights reserved. | ||
| // Licensed under the MIT license. See LICENSE.md file in the project root for full license information. | ||
|
|
||
| package logging | ||
|
|
||
| // #include <stdlib.h> | ||
| // #include <speechapi_c_diagnostics.h> | ||
| // | ||
| // extern void goEventLoggerCallback(const char* logLine); | ||
| // | ||
| // static void cgo_event_logger_callback(const char* logLine) | ||
| // { | ||
| // goEventLoggerCallback(logLine); | ||
| // } | ||
| // | ||
| // uintptr_t cgo_register_event_callback() | ||
| // { | ||
| // return (uintptr_t)diagnostics_logmessage_set_callback(cgo_event_logger_callback); | ||
| // } | ||
| // | ||
| // uintptr_t cgo_unregister_event_callback() | ||
| // { | ||
| // return (uintptr_t)diagnostics_logmessage_set_callback((DIAGNOSTICS_CALLBACK_FUNC)0); | ||
| // } | ||
| import "C" |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.