Typescript SDK: Ontology extension/override for telemetry

We’re using the generated Typescript SDK and have generally found it to work quite well. The main thing that I’ve found wanting is the inability to wrap the Ontology/FoundryClient types due to the #private field that gets generated on the Ontology class:

export declare class Ontology<O extends OntologyDefinition<any>> {
    #private;
    constructor(client: ClientContext<O>);
    get objects(): Objects<O>;
    get actions(): Actions<O>;
    get queries(): Queries<O>;
    get attachments(): Attachments;
}

I’d like to be able to override the objects/actions/queries in order to wrap them with some telemetry, like so:

type WrappedBaseObjectSet<O extends OntologyObject> = Omit<BaseObjectSet<O>, "get" | "select"> & {
    get(primaryKey: O["__primaryKey"]): Promise<Result<O, GetObjectError>>;
    select<T extends keyof SelectableProperties<O>>(
        properties: readonly T[]
    ): FilteredPropertiesTerminalOperationsWithGet<O, T[]>;
};

type WrappedObjects<O extends Ontology["objects"]> = {
    [K in keyof O]: O[K] extends BaseObjectSet<infer T> ? WrappedBaseObjectSet<T> : O[K];
};

function wrapOntologyObjects<O extends Ontology["objects"]>(objects: O): WrappedObjects<O> {
    const wrappedObjects = {} as WrappedObjects<O>;

    Object.entries(objects).forEach(([key, object]) => {
        const k = key as keyof O;
        wrappedObjects[k] = wrapBaseObjectSet(object) as WrappedObjects<O>[typeof k];
    });

    return wrappedObjects;
}

function wrapBaseObjectSet<O extends OntologyObject>(
    baseObjectSet: BaseObjectSet<O>
): WrappedBaseObjectSet<O> {
    return {
        ...baseObjectSet,
        get: async (primaryKey: O["__primaryKey"]) => {
            const start = Date.now();
            const result = await baseObjectSet.get(primaryKey);
            const duration = (Date.now() - start) / 1000;
            ontologySdkApiRequestCounter.inc({
                object_or_action: baseObjectSet.apiName,
                ontology_method: "get",
            });
            ontologySdkApiRequestDuration.observe(
                { object_or_action: baseObjectSet.apiName, ontology_method: "get" },
                duration
            );

            if (result.type === "error") {
                ontologySdkApiErrorCounter.inc({
                    object_or_action: baseObjectSet.apiName,
                    error_type: result.error.errorType,
                    error_name: result.error.errorName,
                    ontology_method: "get",
                });
            }

            return result;
        },
...

and then have some TelemetryFoundryClient that implements or extends FoundryClient generated by the SDK. But because of the #private field in the generated types, the compiler will not allow creating a new Ontology object.

Curious if there are:
a) any other approaches to generating Telemetry for the SDK that is generic
b) any thoughts on the Palantir side on changing this to allow more flexibility

1 Like

Thanks for your feedback!
Have you seen the new Metrics page on the developer console?
Check out Application Metrics on our public docs site.

Happy to hear your thoughts on this and if it is covering the telemetry you are thinking of?

I had not seen that! That’s really great. A couple of things that would be on my “wishlist”:

  • configuring alerts in Developer Console based on these metrics
  • and/or making these metrics accessible programmatically so that we could configure our own alerting

I think it would still be preferable (or better in addition) to be able to wrap the client in order to:
a) pick up on errors that occur outside of the Foundry server-side, e.g., network errors or errors in the SDK code itself
b) “own” the metrics / alerting ourselves; the concern here being that Foundry has an outage, and our ability to detect that is correlated to the outage itself

But these are pretty small asks – having the beta metrics you linked available for alerting would be amazing and solve basically all of our needs

Thanks for the feedback!

The current metrics UI does not have API which could be use for Alerting and also depending of what type of alerting you are looking for, you might have an issue with latency. If I recall the metric latency is about 24 h.

While I am discussing this with both the metrics team and the Typescript team, it would be interesting to drill deeper into your requirements, if you are open for that. hit me on ewitkon @ palantir.com and we can get something setup.

In any case I will get back to you with some feedback.

Following back on this, can you explain what is blocking you from wrapping the object like you suggest above?
If you provide a similar interface to the object and forward the calls to the SDK object what is breaking?