-
Notifications
You must be signed in to change notification settings - Fork 534
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
Session handling implementation #2358
Comments
Nice. This seems like a very reasonable approach. It matches pretty closely with Android, although we don't have an explicit interface: https://github.com/open-telemetry/opentelemetry-android/blob/main/android-agent/src/main/java/io/opentelemetry/android/SessionId.java#L50 Instead of One thing I think is also valuable is to have the event generation (session start, end, change) being decoupled from the |
This isn't necessary for first PR, but any thoughts on global registration for session manager? (eg. via otel-api's registerGlobal/getGlobal) Two use cases that this would greatly simplify:
As a more concrete real world example, for splunk/signalfx we have 2 separate components - core with tracing instrumentation and session replay as extension that relies on first. Since we index RUM data based on session id, want it to be consistent, and some customers use bundled js files while others npm install, then the easiest way is to register our core onto otel global, and component reuses core's Resource & session manager
For example if a site has a live chat-box support, these systems generally include an API that can be used to include custom data on the conversation, so it can be useful to include otel's current session id so it can be used to debug if user has issues with the site. So then there's the similar issue of how to access the session manager ChatBot.onConversationStarted(() => {
ChatBot.updateMetadata({
'otel.session_id': /* get session manger */.getSessionId()
});
}); (in my experience with customers who are all-in on otel they definitely prefer a via otel api approach over via vendor api whenever possible, the lack of vendor lock-in kinda is the selling point of otel for them) on that note why is this issue under contrib? |
@t2t2 I can see how it would be useful to have access to the session ID from a central place. I am not opposed to adding it to the API. I would prefer to not include it in the first version (as you mentioned) in order to get something basic implemented first.
I thought of it as similar to |
To decouple generating session start/end events, I can think of two approaches:
interface SessionObserver {
onSessionStarted(sessionId: string): void;
onSessionEnded(sessionId: string): void;
}
export interface SessionManager {
getSessionId(): string;
addObserver(observer: SessionObserver): void;
}
export interface SessionManager {
getSessionId(): string;
addEventListener(event: string, listener: (...args: any[]) => void): void;
} Maybe the SessionManager interface should be an abstract class instead, so that every implementation does not need to implement its own event emitting mechanism. If we did not need multiple observers/listeners, it would simplify things (similar to Android setSessionIdChangeListener). |
I guess since it is optional and technically optional -> contrib, just to me contrib (like just the existence of the word, regardless of how false the interpretation may be) always has the feel of being on the 2nd level of stuff being supported
I'd vote towards 2nd as it's the pattern js devs would already be used to. Bringing it back to integrating with other systems mentioned above, there can be external APIs that want initial value + call it again with new value when it changes. (and as you can tell from this, supporting multiple listeners definitely something that's gonna be wanted)
There may be value in both - Interface and base class that handles most of the api, expiration checking, session refreshing, ... Maybe in the end implementations really only need to provide getValue (from storage) and setValue. Or even when written functionally interface SessionManager {
getSessionId(): string;
addEventListener(event: string, listener: (...args: any[]) => void): void;
}
function createSessionManager(
options,
getValue: (key: string) => string | undefined | null,
setValue: (key: string, value: string) => void
): SessionManager {
/* all of the logic */
}
function createLocalStorageSessionManager(options: Parameters<typeof createSessionManager>[0]) {
return createSessionManager(
options,
(key) => localStorage.getItem(key),
(key, value) => localStorage.setItem(key, value)
);
}
function createSessionStorageSessionManager(options: Parameters<typeof createSessionManager>[0]) {
return createSessionManager(
options,
(key) => sessionStorage.getItem(key),
(key, value) => sessionStorage.setItem(key, value)
);
}
function createCookieSessionManager(options: Parameters<typeof createSessionManager>[0]) {
return createSessionManager(
options,
(key) => { /* not gonna a full implmentation in example since it's quite a few lines but imagine reading document.cookie */},
(key, value) => document.cookie = /* yeah same */
);
} |
The general approach looks good to me and fits well with the existing thoughts on session management. I don't have specific comments on the implementation, but echoing some of the existing comments, having a component to transition the session from one to state to another, then wrapping an API to broadcast session changes in an idiomatic way for web locally, seems like the core of what this prototype should provide. Additionally, things that can be added later (as mentioned by others too) can be additive to this initial proposal (e.g. firing session change events that can be observed external systems, providing an API that gets the current session ID, configuring how session start and ends are triggered, etc.), so keeping this as tight as possible without needing to change the existing public API methods would be nice. |
Like the design 👍 Commented in the Client-Side SIG but will include it here as well for posterity:
|
I took a stab at this, and it might be tricky. Here is a prototype open-telemetry/opentelemetry-sandbox-web-js#238. Some observations
It seems to me like this might get complicated. I wonder if tracking max duration and inactivity works for majority of users, and for those who want something different, they could implement a different SessionProvider? The lifecycle interface currently looks like this export interface SessionLifecycle {
/** Starts tracking a new session */
start(session: Session): void;
/** Stop tracking the current session, reset to a clear state */
clear(): void;
/** Notifies this class that the session is currently active. */
bumpSessionActive(): void;
/** Register a listener function to call when session is ended. */
onSessionEnded(listener: () => void): void;
}
In the current design, a completely new SessionProvider would have to be implemented. My hope with the SessionManager was to have something that works for most users. |
Thanks for looking into it, I agree that formalizing this would cause more complexity than necessary. I think the prescribed approach would be to implement a new SessionProvider (replace the default SessionManager). That should be enough and providing the SessionManager as a default implementation example should be helpful enough for people would want to customize the behavior. |
Related to #952
This is a proposal to implement sessions for web. The
session.id
attribute is now defined in semantic conventions (link). The attribute should be added to any span or log generated by a web instrumentation.Implementation proposal:
SessionIdSpanProcessor
andSessionIdLogRecordProcessor
SessionManager
web-common
SessionManager interface
A prototype of this proposal is available here.
Prior implementations:
I am looking for any feedback on this approach. If there are no objections, I will open a PR in line with the prototype implementation.
The text was updated successfully, but these errors were encountered: