@grafana/faro-transport-otlp-http
Version:
Faro transport which converts the Faro data model to the Otlp data model.
2 lines (1 loc) • 9.82 kB
JavaScript
var GrafanaFaroTransportOtlpHttp=function(e){"use strict";function t(e,t){var r={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var o=0;for(n=Object.getOwnPropertySymbols(e);o<n.length;o++)t.indexOf(n[o])<0&&Object.prototype.propertyIsEnumerable.call(e,n[o])&&(r[n[o]]=e[n[o]])}return r}function r(e,t){return typeof e===t}"function"==typeof SuppressedError&&SuppressedError;const n=e=>r(e,"string"),o=e=>r(e,"number")&&!isNaN(e)||r(e,"bigint"),s=e=>o(e)&&Number.isInteger(e),i=e=>r(e,"boolean"),a=e=>!(e=>r(e,"null"))(e)&&r(e,"object"),l=e=>function(e,t){return Object.prototype.toString.call(e)===`[object ${t}]`}(e,"Array");var u,c,d;function g(){}!function(e){e.TRACE="trace",e.DEBUG="debug",e.INFO="info",e.LOG="log",e.WARN="warn",e.ERROR="error"}(u||(u={})),u.LOG,u.TRACE,u.DEBUG,u.INFO,u.LOG,u.WARN,u.ERROR,function(e){e.EXCEPTION="exception",e.LOG="log",e.MEASUREMENT="measurement",e.TRACE="trace",e.EVENT="event"}(c||(c={})),c.EXCEPTION,c.LOG,c.MEASUREMENT,c.TRACE,c.EVENT,function(e){e[e.OFF=0]="OFF",e[e.ERROR=1]="ERROR",e[e.WARN=2]="WARN",e[e.INFO=3]="INFO",e[e.VERBOSE=4]="VERBOSE"}(d||(d={}));const v={debug:g,error:g,info:g,prefix:"Faro",warn:g};d.ERROR;const p=Object.assign({},console);class f{constructor(){this.unpatchedConsole=p,this.internalLogger=v,this.config={},this.metas={}}logDebug(...e){this.internalLogger.debug(`${this.name}\n`,...e)}logInfo(...e){this.internalLogger.info(`${this.name}\n`,...e)}logWarn(...e){this.internalLogger.warn(`${this.name}\n`,...e)}logError(...e){this.internalLogger.error(`${this.name}\n`,...e)}}class m extends f{isBatched(){return!1}getIgnoreUrls(){return[]}}const h="1.19.0",b="exception.message",y="exception.type",O="service.name",E="service.version",R="telemetry.sdk.language",L="webjs",T="telemetry.sdk.name",N="telemetry.sdk.version",w="user_agent.original",I="browser.brands",U="browser.language",x="browser.mobile",S="browser.platform",j="deployment.environment.name",k="service.namespace";function D(e){return n(e)?{stringValue:e}:s(e)?{intValue:e}:o(e)?{doubleValue:e}:i(e)?{boolValue:e}:l(e)?{arrayValue:{values:e.map(D)}}:e instanceof Uint8Array?{bytesValue:e}:a(e)?{kvlistValue:{values:Object.entries(e).map((([e,t])=>A(e,t))).filter(B)}}:{}}function A(e,t){if(null!=t&&""!==t)return{key:e,value:D(t)}}function B(e){return Boolean(e)&&"string"==typeof(null==e?void 0:e.key)&&void 0!==(null==e?void 0:e.value)}function F(e,t){function r(e){return{scope:{name:"@grafana/faro-web-sdk",version:h},logRecords:[n(e)]}}function n(r){const{type:n}=r;switch(n){case c.LOG:return function(e){var t,r;const{meta:n,payload:i}=e,a=s(i.timestamp),l=D(i.message);function c(e){switch(e){case u.TRACE:return{severityNumber:1,severityText:"TRACE"};case u.DEBUG:return{severityNumber:5,severityText:"DEBUG"};case u.INFO:return{severityNumber:9,severityText:"INFO"};case u.LOG:return{severityNumber:10,severityText:"INFO2"};case u.WARN:return{severityNumber:13,severityText:"WARN"};case u.ERROR:return{severityNumber:17,severityText:"ERROR"}}}return Object.assign(Object.assign({timeUnixNano:a},c(i.level)),{body:l,attributes:[...o(n),A("faro.log.context",i.context)].filter(B),traceId:null===(t=i.trace)||void 0===t?void 0:t.trace_id,spanId:null===(r=i.trace)||void 0===r?void 0:r.span_id})}(r);case c.EXCEPTION:return function(e){var r,n;const{meta:i,payload:a}=e,l=s(a.timestamp),u=G(e,null==t?void 0:t.createErrorLogBody);return Object.assign(Object.assign({timeUnixNano:l},u?{body:u}:{}),{attributes:[...o(i),A(y,a.type),A(b,a.value),A("faro.error.stacktrace",a.stacktrace),A("faro.error.context",a.context)].filter(B),traceId:null===(r=a.trace)||void 0===r?void 0:r.trace_id,spanId:null===(n=a.trace)||void 0===n?void 0:n.span_id})}(r);case c.EVENT:return function(e){var t,r;const{meta:n,payload:i}=e,a=s(i.timestamp),l=D(i.name);return{timeUnixNano:a,body:l,attributes:[...o(n),A("event.name",i.name),A("event.domain",i.domain),A("event.attributes",i.attributes)].filter(B),traceId:null===(t=i.trace)||void 0===t?void 0:t.trace_id,spanId:null===(r=i.trace)||void 0===r?void 0:r.span_id}}(r);case c.MEASUREMENT:return function(e){var r,n;const{meta:i,payload:a}=e,l=s(a.timestamp),[u,c]=Object.entries(a.values).flat(),d=G(e,null==t?void 0:t.createMeasurementLogBody);return Object.assign(Object.assign({timeUnixNano:l},d?{body:d}:{}),{attributes:[...o(i),A("measurement.type",a.type),A("measurement.name",u),A("measurement.value",c),A("faro.measurement.context",a.context)].filter(B),traceId:null===(r=a.trace)||void 0===r?void 0:r.trace_id,spanId:null===(n=a.trace)||void 0===n?void 0:n.span_id})}(r);default:return null==e||e.error(`Unknown TransportItemType: ${n}`),{}}}function o(e){const{view:t,page:r,session:n,user:o}=e;return[A("view.name",null==t?void 0:t.name),A("url.full",null==r?void 0:r.url),A("page.id",null==r?void 0:r.id),A("page.attributes",null==r?void 0:r.attributes),A("session.id",null==n?void 0:n.id),A("session.attributes",null==n?void 0:n.attributes),A("user.id",null==o?void 0:o.id),A("user.name",null==o?void 0:o.username),A("user.email",null==o?void 0:o.email),A("user.full_name",null==o?void 0:o.fullName),A("user.roles",null==o?void 0:o.roles),A("user.hash",null==o?void 0:o.hash),A("user.attributes",null==o?void 0:o.attributes)].filter(B)}function s(e){return 1e6*Date.parse(e)}return{toResourceLog:function(e){return{resource:C(e),scopeLogs:[r(e)]}},toScopeLog:r,toLogRecord:n}}function C(e){const{browser:t,sdk:r,app:n}=e.meta;return{attributes:[A(x,null==t?void 0:t.mobile),A(w,null==t?void 0:t.userAgent),A(U,null==t?void 0:t.language),A(I,null==t?void 0:t.brands),A(S,null==t?void 0:t.os),A("browser.name",null==t?void 0:t.name),A("browser.version",null==t?void 0:t.version),A("browser.screen_width",null==t?void 0:t.viewportWidth),A("browser.screen_height",null==t?void 0:t.viewportHeight),A(T,null==r?void 0:r.name),A(N,null==r?void 0:r.version),Boolean(r)?A(R,L):void 0,A(O,null==n?void 0:n.name),A(E,null==n?void 0:n.version),A(k,null==n?void 0:n.namespace),A(j,null==n?void 0:n.environment)].filter(B)}}function G(e,t){return"function"==typeof t?D(t(e)):void 0}class P{constructor({internalLogger:e,customOtlpTransform:t,transportItem:r}){this.resourceSpans=[],this.internalLogger=e,this.resourceLogs=[],this.getLogTransforms=F(this.internalLogger,t),this.getTraceTransforms=(this.internalLogger,{toResourceSpan:function(e){var t,r;const n=C(e),o=null===(r=null===(t=e.payload.resourceSpans)||void 0===t?void 0:t[0])||void 0===r?void 0:r.scopeSpans;return{resource:n,scopeSpans:null!=o?o:[]}}}),r&&this.addResourceItem(r)}getPayload(){return{resourceLogs:this.resourceLogs,resourceSpans:this.resourceSpans}}addResourceItem(e){var t,r,n,o;const{type:s}=e;try{switch(s){case c.LOG:case c.EXCEPTION:case c.EVENT:case c.MEASUREMENT:const{toLogRecord:o,toResourceLog:i}=this.getLogTransforms;0===this.resourceLogs.length?this.resourceLogs=[i(e)]:null===(r=null===(t=this.resourceLogs[0])||void 0===t?void 0:t.scopeLogs[0])||void 0===r||r.logRecords.push(o(e));break;case c.TRACE:const{toResourceSpan:a}=this.getTraceTransforms;this.resourceSpans.push(a(e));break;default:null===(n=this.internalLogger)||void 0===n||n.error(`Unknown TransportItemType: ${s}`)}}catch(e){null===(o=this.internalLogger)||void 0===o||o.error(e)}}}return e.OtlpHttpTransport=class extends m{constructor(e){var t,r,n;super(),this.options=e,this.name="@grafana/faro-web-sdk:transport-otlp-http",this.version=h,this.sendingTracesDisabledUntil=new Date,this.sendingLogsDisabledUntil=new Date,this.rateLimitBackoffMs=null!==(t=e.defaultRateLimitBackoffMs)&&void 0!==t?t:5e3,this.promiseBuffer=function(e){const{size:t,concurrency:r}=e,n=[];let o=0;const s=()=>{if(o<r&&n.length){const{producer:e,resolve:t,reject:r}=n.shift();o++,e().then((e=>{o--,s(),t(e)}),(e=>{o--,s(),r(e)}))}};return{add:e=>{if(n.length+o>=t)throw new Error("Task buffer full");return new Promise(((t,r)=>{n.push({producer:e,resolve:t,reject:r}),s()}))}}}({size:null!==(r=null==e?void 0:e.bufferSize)&&void 0!==r?r:30,concurrency:null!==(n=null==e?void 0:e.concurrency)&&void 0!==n?n:5})}getIgnoreUrls(){var e;const{tracesURL:t="",logsURL:r=""}=this.options;return[t,r].filter(Boolean).concat(null!==(e=this.config.ignoreUrls)&&void 0!==e?e:[])}isBatched(){return!0}send(e){const t=new P({internalLogger:this.internalLogger,customOtlpTransform:this.options.otlpTransform});e.forEach((e=>t.addResourceItem(e))),this.sendPayload(t.getPayload())}sendPayload(e){try{const{tracesURL:r="",logsURL:n=""}=this.options;for(const[o,s]of Object.entries(e)){if(!(l(s)&&s.length>0))continue;let e,i=e=>{},a="";switch(o){case"resourceSpans":a=r,e=this.sendingTracesDisabledUntil,i=e=>{this.sendingTracesDisabledUntil=e};break;case"resourceLogs":a=n,e=this.sendingLogsDisabledUntil,i=e=>{this.sendingLogsDisabledUntil=e}}if(e&&e>new Date(Date.now()))return void this.logWarn(`Dropping transport item due to too many requests. Backoff until ${e}`);const u=JSON.stringify({[o]:s}),{requestOptions:c,apiKey:d}=this.options,v=null!=c?c:{},{headers:p}=v,f=t(v,["headers"]);a&&this.promiseBuffer.add((()=>fetch(a,Object.assign({method:"POST",headers:Object.assign(Object.assign({"Content-Type":"application/json"},null!=p?p:{}),d?{"x-api-key":d}:{}),body:u,keepalive:u.length<=6e4},null!=f?f:{})).then((t=>(429===t.status&&(i(this.getRetryAfterDate(t)),this.logWarn(`Too many requests, backing off until ${e}`)),t.text().catch(g),t))).catch((e=>{this.logError("Failed sending payload to the receiver\n",JSON.parse(u),e)}))))}}catch(e){this.logError(e)}}getRetryAfterDate(e){const t=Date.now(),r=e.headers.get("Retry-After");if(r){const e=Number(r);if(!isNaN(e))return new Date(1e3*e+t);const n=Date.parse(r);if(!isNaN(n))return new Date(n)}return new Date(t+this.rateLimitBackoffMs)}},e}({});