Last active
June 30, 2025 13:43
-
-
Save polarnik/c7f34235e1e191245c17722eb3839424 to your computer and use it in GitHub Desktop.
SiteSpeed custom wait function
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
| function defaultPageCompleteCheck(waitTime) { | |
| var end = window.performance.timing.loadEventEnd; | |
| var start = window.performance.timing.navigationStart; | |
| return (end > 0) && (performance.now() > end - start + waitTime); | |
| } | |
| function customWaitTime() { | |
| return 2000; | |
| } | |
| function getRequestByRegEx(resources, regex) { | |
| return resources.find(entry => | |
| entry.name.match(regex) && | |
| entry.initiatorType === "fetch" | |
| ); | |
| } | |
| function measureRequest(request, measureName) { | |
| performance.measure(measureName, { | |
| start: request.startTime, | |
| duration: request.responseEnd - request.startTime | |
| }); | |
| } | |
| /** | |
| * Calculate summary PerformanceResourceTiming by groups: | |
| * | |
| * Name-based groups are metrics by domains: | |
| * - "youtrack" group: names started with "https://youtrack.jetbrains.com/" | |
| * - "hub" group: names started with "https://hub.jetbrains.com/" | |
| * - "other" group: other names | |
| * | |
| * Groups by fields: | |
| * - contentType ("text/javascript", "image/png", etc.) | |
| * - deliveryType ("cache", "") | |
| * - initiatorType ("script", "link", "img", "fetch", etc.) | |
| * - nextHopProtocol ("", "h2", "h3", etc.) | |
| * - renderBlockingStatus ("blocking" or "non-blocking") | |
| * - responseStatus (200, 400, 500, etc.) | |
| * | |
| * The key object has string fields: | |
| * - domain_group | |
| * - contentType | |
| * - initiatorType | |
| * - nextHopProtocol | |
| * - renderBlockingStatus | |
| * - responseStatus | |
| * | |
| * The function prepares the list of objects with all combinations of group values | |
| * based on the PerformanceResourceTiming[] entries. | |
| * | |
| * The values are values | |
| * | |
| * @param resources : PerformanceResourceTiming[] | |
| */ | |
| function measureResources(resources) { | |
| const youtrackRequests = resources.filter(resource => { | |
| resource.name.startsWith("https://youtrack.jetbrains.com/") | |
| }); | |
| const hubRequests = resources.filter(resource => { | |
| resource.name.startsWith("https://hub.jetbrains.com/") | |
| }); | |
| } | |
| function waitRequest(request, name, waitTime) { | |
| // If the request is found and completed | |
| if (request && request.responseEnd > 0) { | |
| // Check if enough time has passed since the request completed | |
| const status = performance.now() > request.responseEnd + customWaitTime(); | |
| if(status) { | |
| measureRequest(request, name); | |
| return true; | |
| } else | |
| return defaultPageCompleteCheck(waitTime); | |
| } else | |
| return defaultPageCompleteCheck(waitTime); | |
| } | |
| function waitTwoRequests(request1, name1, request2, name2, waitTime) { | |
| if (request1 && request2 && | |
| request1.responseEnd > 0 && | |
| request2.responseEnd > 0) { | |
| // Check if enough time has passed since the last request completed | |
| const lastRequestEnd = Math.max(request1.responseEnd, request2.responseEnd); | |
| const status = performance.now() > lastRequestEnd + customWaitTime(); | |
| if(status) { | |
| measureRequest(request1, name1); | |
| measureRequest(request2, name2); | |
| return true; | |
| } else return defaultPageCompleteCheck(waitTime); | |
| } else | |
| return defaultPageCompleteCheck(waitTime); | |
| } | |
| /** | |
| * Wait key HTTP Requests | |
| * of the issue list page (https://youtrack.jetbrains.com/agiles/153-1739/current) | |
| * | |
| * The key request is | |
| * - (POST) https://youtrack.jetbrains.com/api/issuesGetter?_top=-1&_topLinks=3&fields=attachments(id),fields(_type,hasStateMachine,id,isUpdatable,name,projectCustomField(_type,bundle(id),canBeEmpty,emptyFieldText,field(fieldType(isMultiValue,valueType),id,localizedName,name,ordinal),id,isEstimation,isPublic,isSpentTime,ordinal,size),value(_type,archived,avatarUrl,buildIntegration,buildLink,color(background,foreground,id),description,fullName,id,isResolved,localizedName,login,markdownText,minutes,name,presentation,ringId,text)),id,idReadable,isDraft,numberInProject,project(_type,archived,id,name,plugins(timeTrackingSettings(enabled,estimate(field(id,name),id),timeSpent(field(id,name),id))),projectType(id),ringId,shortName),reporter(_type,id,login,ringId),resolved,subtasks(id,issuesSize,unresolvedIssuesSize) | |
| * | |
| * The method measures duration of POST/api/issuesGetter | |
| * @param resources | |
| * @param waitTime | |
| */ | |
| function agile_Boards_Kotlin_Notebook_PageCompleteCheck(resources, waitTime) { | |
| try { | |
| const postRequest = getRequestByRegEx(resources, "/api/issuesGetter"); | |
| return waitRequest(postRequest, "GET/api/issuesGetter", waitTime); | |
| // TODO: Wait by selectors | |
| } catch (e) { | |
| console.log(`agile_Boards_Kotlin_Notebook_PageCompleteCheck: exception: \n${e}`); | |
| return true; | |
| } | |
| } | |
| function issue_IDEA_PageCompleteCheck(waitTime) { | |
| return issue_YouTrack_PageCompleteCheck(waitTime); | |
| } | |
| /** | |
| * Wait key HTTP Requests | |
| * of the issue list page (https://youtrack.jetbrains.com/issue/JT-32215) | |
| * | |
| * The key requests are: | |
| * - (GET) https://youtrack.jetbrains.com/api/issues/JT-32215/links?_topLinks=25&fields=id,direction(),linkType(id,directed,aggregation,sourceToTarget,targetToSource,localizedSourceToTarget,localizedTargetToSource),issuesSize,trimmedIssues(id,idReadable,summary,reporter(id,ringId,login,name,email,isEmailVerified,guest,fullName,avatarUrl,online,banned,banBadge,canReadProfile,isLocked,userType(id),issueRelatedGroup(%40permittedGroups)),resolved,fields(value(id,minutes,presentation,isEstimation,isSpentTime,name,description,localizedName,isResolved,color(id,background,foreground),buildIntegration,buildLink,text,ringId,login,email,isEmailVerified,guest,fullName,avatarUrl,online,banned,banBadge,canReadProfile,isLocked,userType(id),issueRelatedGroup(%40permittedGroups),allUsersGroup,_type(),icon,teamForProject(name,shortName)),id,_type,hasStateMachine,isUpdatable,projectCustomField(_type,id,field(id,name,ordinal,aliases,localizedName,fieldType(id,presentation,isBundleType,valueType,isMultiValue)),bundle(id,_type),canBeEmpty,emptyFieldText,hasRunningJob,ordinal,isSpentTime,isEstimation,isPublic),visibleOnList,searchResults(id,textSearchResult(highlightRanges(%40textRange),textRange(%40textRange))),pausedTime),project(id,ringId,name,shortName,projectType(id),pinned,iconUrl,template,archived,hasArticles,isDemo,sourceTemplate,fieldsSorted,query,issuesUrl,restricted,leader(%40permittedUsers),creationTime,widgets(id,key,appId,description,appName,appTitle,name,collapsed,configurable,indexPath,extensionPoint,iconPath,appIconPath,appDarkIconPath,defaultHeight,defaultWidth,expectedHeight,expectedWidth,vendorName,vendorEmail,vendorUrl,marketplaceId),plugins(timeTrackingSettings(id,enabled),helpDeskSettings(id,defaultForm(uuid,title)),vcsIntegrationSettings(hasVcsIntegrations),grazie(disabled))),visibility(_type,implicitPermittedUsers(%40permittedUsers),permittedGroups(%40permittedGroups),permittedUsers(%40permittedUsers)),watchers(hasStar))%3B%40permittedUsers%3Aid,ringId,login,name,email,isEmailVerified,guest,fullName,avatarUrl,online,banned,banBadge,canReadProfile,isLocked,userType(id)%3B%40permittedGroups%3Aid,name,ringId,allUsersGroup,_type(),icon,teamForProject(name,shortName)%3B%40textRange%3AstartOffset,endOffset&customFields=Priority | |
| * - (GET) https://youtrack.jetbrains.com/api/issues/JT-32215/activitiesPage?categories=IssueCreatedCategory,CommentsCategory&reverse=true&fields=activities(category(id()),added(id,ringId,login,name,email,isEmailVerified,guest,fullName,avatarUrl,online,banned,banBadge,canReadProfile,isLocked,userType(id),localizedName,numberInProject,project(name,shortName),author(id,ringId,avatarUrl,canReadProfile,isLocked,login,name,email,isEmailVerified,guest,fullName,online,banned,banBadge,userType(id)),created,updated,mimeType,url,size,visibility(%40visibility),imageDimensions(width,height),thumbnailURL,recognizedText,searchResults(%40searchResults),comment(%40comment),embeddedIntoDocument(id),embeddedIntoComments(id),idReadable,summary,resolved,creator(%40value1),text,type(%40value),duration(minutes,presentation),textPreview,date,usesMarkdown,attributes(id,name,value(%40value)),mentionedUsers(%40author),mentionedIssues(id,idReadable,summary,reporter(%40author),updater(%40author),resolved,updated,created,unauthenticatedReporter,fields(value(id,minutes,presentation,isEstimation,isSpentTime,name,description,localizedName,isResolved,color(%40color),buildIntegration,buildLink,text,ringId,login,email,isEmailVerified,guest,fullName,avatarUrl,online,banned,banBadge,canReadProfile,isLocked,userType(id),issueRelatedGroup(%40issueRelatedGroup),allUsersGroup,_type(),icon,teamForProject(name,shortName)),id,_type,hasStateMachine,isUpdatable,projectCustomField(_type,id,field(id,name,ordinal,aliases,localizedName,fieldType(id,presentation,isBundleType,valueType,isMultiValue)),bundle(id,_type),canBeEmpty,emptyFieldText,hasRunningJob,ordinal,isSpentTime,isEstimation,isPublic),visibleOnList,searchResults(id,textSearchResult(highlightRanges(%40highlightRanges),textRange(%40highlightRanges))),pausedTime),project(%40project),visibility(%40visibility),tags(%40tags),votes,voters(hasVote),watchers(hasStar),usersTyping(timestamp,user(%40value1)),canUndoComment),mentionedArticles(id,idReadable,reporter(%40value1),summary,project(%40project),parentArticle(idReadable),ordinal,visibility(%40visibility),hasUnpublishedChanges,hasChildren,tags(%40tags),hasStar),files,commands(errorText,hasError,start,end),noHubUserReason(_type,id),noUserReason(_type,id),pullRequest(_type,author(%40value1),date,fetched,processor(id,_type),files,id,branch,idExternal,idReadable,noHubUserReason(_type,id),noUserReason(_type,id),title,text,url),urls,processors(id,_type),state(_type,id),version,deleted,pinned,attachments(id,name,author(%40author1),created,updated,mimeType,url,size,visibility(%40visibility),imageDimensions(width,height),thumbnailURL,recognizedText,searchResults(%40searchResults),comment(%40comment),embeddedIntoDocument(id),embeddedIntoComments(id)),reactions(id,reaction,author(%40value1)),reactionOrder,hasEmail,canUpdateVisibility,suspiciousEmail,issue(id,project(id)),markdownEmbeddings(key,settings,widget(id)),reaction,presentation),removed(id,ringId,login,name,email,isEmailVerified,guest,fullName,avatarUrl,online,banned,banBadge,canReadProfile,isLocked,userType(id),localizedName,numberInProject,project(name,shortName),author(%40author1),created,updated,mimeType,url,size,visibility(%40visibility),imageDimensions(width,height),thumbnailURL,recognizedText,searchResults(%40searchResults),comment(%40comment),embeddedIntoDocument(id),embeddedIntoComments(id),idReadable,summary,resolved,presentation),issue(description,customFields(name,projectCustomField(emptyFieldText,field(id,localizedName,name,fieldType(%40fieldType))),value(%40value1))),id,author(%40author),authorGroup(id),timestamp,field(id,presentation,customField(fieldType(%40fieldType))),target(id,_type),targetMember,type,pseudo,emptyFieldText,sprintsDisabled),hasBefore,hasAfter,beforeCursor,afterCursor,cursor%3B%40project%3Aid,ringId,name,shortName,projectType(id),pinned,iconUrl,template,archived,hasArticles,isDemo,sourceTemplate,fieldsSorted,query,issuesUrl,restricted,leader(%40value1),creationTime,widgets(id,key,appId,description,appName,appTitle,name,collapsed,configurable,indexPath,extensionPoint,iconPath,appIconPath,appDarkIconPath,defaultHeight,defaultWidth,expectedHeight,expectedWidth,vendorName,vendorEmail,vendorUrl,marketplaceId),plugins(timeTrackingSettings(id,enabled),helpDeskSettings(id,defaultForm(uuid,title)),vcsIntegrationSettings(hasVcsIntegrations),grazie(disabled))%3B%40comment%3Aid,visibility(%40visibility)%3B%40visibility%3A_type,implicitPermittedUsers(%40value1),permittedGroups(%40issueRelatedGroup),permittedUsers(%40value1)%3B%40author%3Aid,ringId,login,name,email,isEmailVerified,guest,fullName,avatarUrl,online,banned,banBadge,canReadProfile,isLocked,userType(id),issueRelatedGroup(%40issueRelatedGroup)%3B%40value%3Aid,name,autoAttach,description,hasRunningJobs,color(%40color),attributes(id,timeTrackingSettings(id,project(id)))%3B%40value1%3Aid,ringId,login,name,email,isEmailVerified,guest,fullName,avatarUrl,online,banned,banBadge,canReadProfile,isLocked,userType(id)%3B%40issueRelatedGroup%3Aid,name,ringId,allUsersGroup,_type(),icon,teamForProject(name,shortName)%3B%40tags%3Aid,name,color(%40color),isDeletable,isUpdatable,isUsable%3B%40searchResults%3AtextSearchResult(highlightRanges(%40highlightRanges))%3B%40author1%3Aid,ringId,avatarUrl,canReadProfile,isLocked,login,name%3B%40color%3Aid,background,foreground%3B%40fieldType%3AvalueType,isMultiValue%3B%40highlightRanges%3AstartOffset,endOffset | |
| * | |
| * The method measures duration of GET/api/issues/{ID}/links and GET/api/issues/{ID}/activitiesPage | |
| * @param waitTime | |
| */ | |
| function issue_YouTrack_PageCompleteCheck(waitTime) { | |
| try { | |
| // Get all resource timing entries | |
| const resources = performance.getEntriesByType("resource"); | |
| const linksRequest = getRequestByRegEx(resources, "/api/issues/[^/]+/links"); | |
| const activitiesRequest = getRequestByRegEx(resources, "/api/issues/[^/]+/activitiesPage"); | |
| return waitTwoRequests(linksRequest, "GET/api/issues/{ID}/links", | |
| activitiesRequest, "GET/api/issues/{ID}/activitiesPage", waitTime); | |
| } catch (e) { | |
| console.log(`issue_YouTrack_PageCompleteCheck: exception: \n${e}`); | |
| return true; | |
| } | |
| } | |
| /** | |
| * Wait key HTTP Requests | |
| * of the issue list page (https://youtrack.jetbrains.com/issues) | |
| * | |
| * The keys request is: | |
| * - (POST) https://youtrack.jetbrains.com/api/issuesGetter?_top=-1&_skip=0&referringQuery=&fields=id,idReadable,summary,reporter(%40updater),updater(%40updater),resolved,updated,created,unauthenticatedReporter,fields(value(id,minutes,presentation,isEstimation,isSpentTime,name,description,localizedName,isResolved,color(%40color),buildIntegration,buildLink,text,ringId,login,email,isEmailVerified,guest,fullName,avatarUrl,online,banned,banBadge,canReadProfile,isLocked,userType(id),issueRelatedGroup(%40permittedGroups),allUsersGroup,_type(),icon,teamForProject(name,shortName)),id,_type,hasStateMachine,isUpdatable,projectCustomField(_type,id,field(id,name,ordinal,aliases,localizedName,fieldType(id,presentation,isBundleType,valueType,isMultiValue)),bundle(id,_type),canBeEmpty,emptyFieldText,hasRunningJob,ordinal,isSpentTime,isEstimation,isPublic),visibleOnList,searchResults(id,textSearchResult(highlightRanges(%40textRange),textRange(%40textRange))),pausedTime),project(id,ringId,name,shortName,projectType(id),pinned,iconUrl,template,archived,hasArticles,isDemo,sourceTemplate,fieldsSorted,query,issuesUrl,restricted,leader(%40user),creationTime,widgets(id,key,appId,description,appName,appTitle,name,collapsed,configurable,indexPath,extensionPoint,iconPath,appIconPath,appDarkIconPath,defaultHeight,defaultWidth,expectedHeight,expectedWidth,vendorName,vendorEmail,vendorUrl,marketplaceId),plugins(timeTrackingSettings(id,enabled),helpDeskSettings(id,defaultForm(uuid,title)),vcsIntegrationSettings(hasVcsIntegrations),grazie(disabled))),visibility(_type,implicitPermittedUsers(%40user),permittedGroups(%40permittedGroups),permittedUsers(%40user)),tags(id,name,color(%40color),isDeletable,isUpdatable,isUsable),votes,voters(hasVote),watchers(hasStar),usersTyping(timestamp,user(%40user)),canUndoComment%3B%40updater%3Aid,ringId,login,name,email,isEmailVerified,guest,fullName,avatarUrl,online,banned,banBadge,canReadProfile,isLocked,userType(id),issueRelatedGroup(%40permittedGroups)%3B%40user%3Aid,ringId,login,name,email,isEmailVerified,guest,fullName,avatarUrl,online,banned,banBadge,canReadProfile,isLocked,userType(id)%3B%40permittedGroups%3Aid,name,ringId,allUsersGroup,_type(),icon,teamForProject(name,shortName)%3B%40color%3Aid,background,foreground%3B%40textRange%3AstartOffset,endOffset&fieldsVisibleOnList=false | |
| * | |
| * The method measures the durations of the (POST) /api/issuesGetter request and response. | |
| * @param waitTime | |
| */ | |
| function issues_PageCompleteCheck(waitTime) { | |
| try { | |
| // Get all resource timing entries | |
| // https://developer.mozilla.org/en-US/docs/Web/API/Performance/getEntriesByType | |
| // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming | |
| const resources = performance.getEntriesByType("resource"); | |
| const postRequest = getRequestByRegEx(resources, "/api/issuesGetter[?]"); | |
| return waitRequest(postRequest, "POST/api/issuesGetter", waitTime); | |
| } catch (e) { | |
| console.log(`issues_PageCompleteCheck: exception: \n${e}`); | |
| return true; | |
| } | |
| } | |
| function project_IntelliJ_IDEA_PageCompleteCheck(waitTime) { | |
| return project_YouTrack_PageCompleteCheck(waitTime); | |
| } | |
| /** | |
| * Wait key HTTP Requests | |
| * of the project page YouTrack (https://youtrack.jetbrains.com/projects/22-1) | |
| * | |
| * The key requests are | |
| * - (GET) /api/issueFolders/22-1/sortOrder/issues?fields=id,idReadable,summary,resolved,fields(id,value(id,name,localizedName,login,avatarUrl,name,presentation,minutes,color(id,foreground,background)),projectCustomField(id,bundle(id),field(id,name,localizedName,fieldType(id,valueType))))&query=%23Unresolved%20sort%20by%3A%20votes%20&$top=50&$skip=0 | |
| * - (POST) /api/issuesGetter/count?fields=count | |
| * | |
| * The method measures the durations of the first (GET) /api/issueFolders/{ID}/sortOrder/issues request and response. | |
| * The method waits the second (POST) /api/issuesGetter/count?fields=count response | |
| * @param waitTime | |
| */ | |
| function project_YouTrack_PageCompleteCheck(waitTime) { | |
| try { | |
| const resources = performance.getEntriesByType("resource"); | |
| const getRequest = getRequestByRegEx(resources, "/api/issueFolders/[^/]+/sortOrder/issues"); | |
| return waitRequest(getRequest, "GET/api/issueFolders/{ID}/sortOrder/issues", waitTime); | |
| } catch (e) { | |
| console.log(`project_YouTrack_PageCompleteCheck: exception: \n${e}`); | |
| return true; | |
| } | |
| } | |
| function addCusomMetrics() { | |
| try { | |
| const entries = performance.getEntriesByType("navigation"); | |
| const entry = entries[0]; | |
| performance.measure(`Redirect`, | |
| { | |
| start: entry.startTime, | |
| duration: entry.workerStart - entry.startTime, | |
| } | |
| ); | |
| performance.measure(`ServiceWorker`, | |
| { | |
| start: entry.workerStart, | |
| duration: entry.domainLookupStart - entry.workerStart, | |
| } | |
| ); | |
| performance.measure(`DNS`, | |
| { | |
| start: entry.domainLookupStart, | |
| duration: entry.domainLookupEnd - entry.domainLookupStart, | |
| } | |
| ); | |
| performance.measure(`TCP`, | |
| { | |
| start: entry.domainLookupEnd, | |
| duration: entry.secureConnectionStart - entry.domainLookupEnd, | |
| } | |
| ); | |
| performance.measure(`TLS`, | |
| { | |
| start: entry.secureConnectionStart, | |
| duration: entry.requestStart - entry.secureConnectionStart, | |
| } | |
| ); | |
| performance.measure(`Request`, | |
| { | |
| start: entry.requestStart, | |
| duration: entry.finalResponseHeadersStart - entry.requestStart, | |
| } | |
| ); | |
| performance.measure(`Response`, | |
| { | |
| start: entry.finalResponseHeadersStart, | |
| duration: entry.responseEnd - entry.finalResponseHeadersStart, | |
| } | |
| ); | |
| performance.measure(`Processing`, | |
| { | |
| start: entry.responseEnd, | |
| duration: entry.loadEventStart - entry.responseEnd, | |
| } | |
| ); | |
| performance.measure(`Load`, | |
| { | |
| start: entry.loadEventStart, | |
| duration: entry.loadEventEnd - entry.loadEventStart, | |
| } | |
| ); | |
| } catch (e) { | |
| console.log(`defaultPageCompleteCheck: exception: \n${(e)}`) | |
| } | |
| } | |
| function get_status(waitTime) { | |
| let status = false; | |
| try { | |
| const entries = performance.getEntriesByType("navigation"); | |
| if(entries && entries.length > 0) { | |
| const entry = entries[0]; | |
| // Get all resource timing entries | |
| const resources = performance.getEntriesByType("resource"); | |
| if (entry.name.includes("test=PreUrl")) { | |
| status = defaultPageCompleteCheck(waitTime); | |
| } else if (entry.name.includes("youtrack.jetbrains.com")) { | |
| if(entry.name.includes("/issue/")) | |
| status = issue_YouTrack_PageCompleteCheck(resources, waitTime); | |
| else if(entry.name.includes("/issues")) | |
| status = issues_PageCompleteCheck(resources, waitTime); | |
| else if(entry.name.includes("/agiles/")) | |
| status = agile_Boards_Kotlin_Notebook_PageCompleteCheck(resources, waitTime); | |
| else if(entry.name.includes("/projects/")) | |
| status = project_YouTrack_PageCompleteCheck(resources, waitTime) | |
| else | |
| status = defaultPageCompleteCheck(waitTime) | |
| } | |
| } else { | |
| status = false; | |
| } | |
| } catch (e) { | |
| console.log(`defaultPageCompleteCheck: exception: \n${(e)}`); | |
| status = true; | |
| } | |
| return status; | |
| } | |
| return (function(waitTime) { | |
| if(get_status(waitTime)) { | |
| addCusomMetrics(); | |
| return true; | |
| } else { | |
| return false; | |
| } | |
| })(arguments[arguments.length - 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
| function getNamePattern(name) { | |
| let group = ""; | |
| if(name.includes("https://youtrack.jetbrains.com/")) { | |
| group = "youtrack" | |
| } else if(name.includes("https://hub.jetbrains.com/")) { | |
| group = "hub" | |
| } else { | |
| group = "other" | |
| } | |
| const parts = name.split("/"); | |
| if(group == "other") { | |
| return group | |
| } else { | |
| if(parts.length >= 3) { | |
| if(parts[3].includes("?") || parts[3].includes("#")) | |
| return group + "/" + "other"; | |
| else | |
| return group + "/" + parts[3]; | |
| } else { | |
| return group | |
| } | |
| } | |
| } | |
| /** | |
| * @param entry : PerformanceResourceTiming | |
| * @param name : String | |
| * @param value : number | |
| */ | |
| function putMetric(metrics, entry, name, value) { | |
| console.log("putMetric"); | |
| console.log(`metrics 1:\n`); | |
| JSON.stringify(metrics); | |
| console.log(`name:\n`); | |
| JSON.stringify(name) | |
| console.log(`value:\n`); | |
| JSON.stringify(value) | |
| const pattern = getNamePattern(entry.name); | |
| let deliveryType = "non-cache"; | |
| if(entry.deliveryType) { | |
| if(entry.deliveryType === "") { | |
| deliveryType = "non-cache" | |
| } else { | |
| deliveryType = entry.deliveryType; | |
| } | |
| } else { | |
| if(entry.decodedBodySize > 0 && entry.transferSize === 0) { | |
| deliveryType = "cache" | |
| } else { | |
| deliveryType = "non-cache" | |
| } | |
| } | |
| if(!(metrics[name])) | |
| metrics[name] = {}; | |
| if(!(metrics[name][deliveryType])) | |
| metrics[name][deliveryType] = {}; | |
| if(!(metrics[name][deliveryType][pattern])) | |
| metrics[name][deliveryType][pattern] = 0.0; | |
| if(!(metrics[name][deliveryType]["ALL"])) | |
| metrics[name][deliveryType]["ALL"] = 0.0; | |
| if(!(metrics[name]["ALL"])) | |
| metrics[name]["ALL"] = {}; | |
| if(!(metrics[name]["ALL"]["ALL"])) | |
| metrics[name]["ALL"]["ALL"] = 0.0; | |
| metrics[name][deliveryType][pattern] += Math.max(value, 0.0); | |
| metrics[name][deliveryType]["ALL"] += Math.max(value, 0.0); | |
| metrics[name]["ALL"]["ALL"] += Math.max(value, 0.0); | |
| console.log(`metrics 2:\n ${JSON.stringify(metrics)}`); | |
| return metrics; | |
| } | |
| function createPerformanceMeasurements(metrics) { | |
| console.log("createPerformanceMeasurements"); | |
| console.log(`metrics:\n`); | |
| JSON.stringify(metrics); | |
| for(const metricName of Object.keys(metrics)) { | |
| for(const deliveryType of Object.keys(metrics[metricName])) { | |
| for(const pattern of Object.keys(metrics[metricName][deliveryType])) { | |
| performance.measure(`custom.${metricName}.${deliveryType}.${pattern}`, | |
| { | |
| start: 0, | |
| duration: metrics[metricName][deliveryType][pattern], | |
| } | |
| ); | |
| } | |
| } | |
| } | |
| } | |
| function addCusomMetrics_total() { | |
| console.log("addCusomMetrics_total"); | |
| try { | |
| const entries = performance.getEntriesByType("resource"); | |
| console.log(`addCusomMetrics_total: entries :\n`); | |
| JSON.stringify(entries); | |
| let metrics = {}; | |
| for(const entry of entries) { | |
| if(entry.entryType === "resource") { | |
| metrics = putMetric(metrics, entry, "Count", 1); | |
| // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming#typical_resource_timing_metrics | |
| // Measuring redirection time (redirectEnd - redirectStart) | |
| // metrics = putMetric(metrics, entry, "Redirect", entry.redirectEnd - entry.redirectStart); | |
| // // !!!!! Measuring ServiceWorker processing time (fetchStart - workerStart) | |
| // metrics = putMetric(metrics, entry, "ServiceWorker", entry.fetchStart - entry.workerStart); | |
| // // Measuring DNS lookup time (domainLookupEnd - domainLookupStart) | |
| // metrics = putMetric(metrics, entry, "DNS", entry.domainLookupEnd - entry.domainLookupStart); | |
| // // Measuring TCP handshake time (connectEnd - connectStart) | |
| // metrics = putMetric(metrics, entry, "TCP_handshake", entry.connectEnd - entry.connectStart); | |
| // // Measuring interim request time (firstInterimResponseStart - finalResponseHeadersStart) | |
| // metrics = putMetric(metrics, entry, "Interim_Request", entry.firstInterimResponseStart - entry.finalResponseHeadersStart); | |
| // | |
| // // Zero-safe | |
| // metrics = putMetric(metrics, entry, "TCP", entry.secureConnectionStart - entry.domainLookupEnd); | |
| // // Zero-safe, Measuring TLS negotiation time (requestStart - secureConnectionStart) | |
| // metrics = putMetric(metrics, entry, "TLS", entry.requestStart - entry.secureConnectionStart); | |
| // // Zero-safe | |
| // metrics = putMetric(metrics, entry, "Request", entry.responseStart - entry.requestStart); | |
| // // !!!!! | |
| // metrics = putMetric(metrics, entry, "Response", entry.responseEnd - entry.responseStart); | |
| // Measuring time to fetch (without redirects) (responseEnd - fetchStart) | |
| metrics = putMetric(metrics, entry, "TimeToFetch", entry.responseEnd - entry.fetchStart); | |
| metrics = putMetric(metrics, entry, "duration", entry.duration); | |
| // metrics = putMetric(metrics, entry, "transferSize", entry.transferSize); | |
| // metrics = putMetric(metrics, entry, "decodedBodySize", entry.decodedBodySize); | |
| // metrics = putMetric(metrics, entry, "encodedBodySize", entry.encodedBodySize); | |
| } | |
| /** | |
| * connectEnd: 0 | |
| * connectStart: 0 | |
| * decodedBodySize: 0 | |
| * domainLookupEnd: 0 | |
| * domainLookupStart: 0 | |
| * encodedBodySize: 0 | |
| * redirectEnd: 0 | |
| * redirectStart: 0 | |
| * requestStart: 0 | |
| * responseStart: 0 | |
| * responseStatus: 0 | |
| * secureConnectionStart: 0 | |
| * transferSize: 0 | |
| * workerStart: 0 | |
| * | |
| * duration: 78 | |
| * startTime: 2632 | |
| * responseEnd: 2710 | |
| * fetchStart: 2632 | |
| */ | |
| } | |
| createPerformanceMeasurements(metrics); | |
| } catch (e) { | |
| console.log(`addCusomMetrics_total: exception: \n${(e)}`) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment