This repository was archived by the owner on Apr 11, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 114
Kiali 1906 Jaeger Integration #965
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
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
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,62 @@ | ||
| import { ActionType, createAction, createStandardAction } from 'typesafe-actions'; | ||
|
|
||
| enum JaegerActionKeys { | ||
| SET_URL = 'SET_URL', | ||
| SERVICE_REQUEST_STARTED = 'SERVICE_REQUEST_STARTED', | ||
| SERVICE_SUCCESS = 'SERVICE_SUCCESS', | ||
| SERVICE_FAILED = 'SERVICE_FAILED', | ||
| SET_SERVICE = 'SET_SERVICE', | ||
| SET_NAMESPACE = 'SET_NAMESPACE', | ||
| SET_LOOKBACK = 'SET_LOOKBACK', | ||
| SET_LOOKBACK_CUSTOM = 'SET_LOOKBACK_CUSTOM', | ||
| SET_SEARCH_REQUEST = 'SET_SEARCH_REQUEST', | ||
| SET_TAGS = 'SET_TAGS', | ||
| SET_LIMIT = 'SET_LIMIT', | ||
| SET_DURATIONS = 'SET_DURATIONS', | ||
|
|
||
| // RESULTS VISUALZIATION OPTIONS | ||
| SET_SEARCH_GRAPH_TO_HIDE = 'SET_SEARCH_GRAPH_TO_HIDE', | ||
|
|
||
| // TRACE VISUALIZATION OPTIONS | ||
| SET_TRACE_MINIMAP_TO_SHOW = 'SET_TRACE_MINIMAP_TO_SHOW', | ||
| SET_TRACE_DETAILS_TO_SHOW = 'SET_TRACE_DETAILS_TO_SHOW' | ||
| } | ||
|
|
||
| // synchronous action creators | ||
| export const JaegerActions = { | ||
| setUrl: createAction(JaegerActionKeys.SET_URL, resolve => (url: string) => | ||
| resolve({ | ||
| url: url | ||
| }) | ||
| ), | ||
| requestStarted: createAction(JaegerActionKeys.SERVICE_REQUEST_STARTED), | ||
| requestFailed: createAction(JaegerActionKeys.SERVICE_FAILED), | ||
| receiveList: createAction(JaegerActionKeys.SERVICE_SUCCESS, resolve => (newList: string[]) => | ||
| resolve({ | ||
| list: newList | ||
| }) | ||
| ), | ||
| setService: createStandardAction(JaegerActionKeys.SET_SERVICE)<string>(), | ||
| setNamespace: createStandardAction(JaegerActionKeys.SET_NAMESPACE)<string>(), | ||
| setLookback: createStandardAction(JaegerActionKeys.SET_LOOKBACK)<string>(), | ||
| setTags: createStandardAction(JaegerActionKeys.SET_TAGS)<string>(), | ||
| setLimit: createStandardAction(JaegerActionKeys.SET_LIMIT)<number>(), | ||
| setSearchRequest: createStandardAction(JaegerActionKeys.SET_SEARCH_REQUEST)<string>(), | ||
| setSearchGraphToHide: createStandardAction(JaegerActionKeys.SET_SEARCH_GRAPH_TO_HIDE)<boolean>(), | ||
| setMinimapToShow: createStandardAction(JaegerActionKeys.SET_TRACE_MINIMAP_TO_SHOW)<boolean>(), | ||
| setDetailsToShow: createStandardAction(JaegerActionKeys.SET_TRACE_DETAILS_TO_SHOW)<boolean>(), | ||
| setCustomLookback: createAction(JaegerActionKeys.SET_LOOKBACK_CUSTOM, resolve => (start: string, end: string) => | ||
| resolve({ | ||
| start: start, | ||
| end: end | ||
| }) | ||
| ), | ||
| setDurations: createAction(JaegerActionKeys.SET_DURATIONS, resolve => (min: string, max: string) => | ||
| resolve({ | ||
| min: min, | ||
| max: max | ||
| }) | ||
| ) | ||
| }; | ||
|
|
||
| export type JaegerAction = ActionType<typeof JaegerActions>; |
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,125 @@ | ||
| import { JaegerActions } from './JaegerActions'; | ||
|
|
||
| import * as Api from '../services/Api'; | ||
|
|
||
| import { ServiceOverview } from '../types/ServiceList'; | ||
| import { KialiAppState } from '../store/Store'; | ||
| import { ThunkDispatch } from 'redux-thunk'; | ||
| import { KialiAppAction } from './KialiAppAction'; | ||
| import { JAEGER_QUERY } from '../config'; | ||
| import logfmtParser from 'logfmt/lib/logfmt_parser'; | ||
| import moment from 'moment'; | ||
|
|
||
| export const convTagsLogfmt = (tags: string) => { | ||
| if (!tags) { | ||
| return null; | ||
| } | ||
| const data = logfmtParser.parse(tags); | ||
| Object.keys(data).forEach(key => { | ||
| const value = data[key]; | ||
| // make sure all values are strings | ||
| // https://github.com/jaegertracing/jaeger/issues/550#issuecomment-352850811 | ||
| if (typeof value !== 'string') { | ||
| data[key] = String(value); | ||
| } | ||
| }); | ||
| return JSON.stringify(data); | ||
| }; | ||
|
|
||
| export class JaegerURLSearch { | ||
| url: string; | ||
|
|
||
| constructor(url: string) { | ||
| this.url = `${url}${JAEGER_QUERY().PATH}?${JAEGER_QUERY().EMBED.UI_EMBED}=${JAEGER_QUERY().EMBED.VERSION}`; | ||
| } | ||
|
|
||
| addQueryParam(param: string, value: string | number) { | ||
| this.url += `&${param}=${value}`; | ||
| } | ||
|
|
||
| addParam(param: string) { | ||
| this.url += `&${param}`; | ||
| } | ||
| } | ||
|
|
||
| export const getUnixTimeStampInMSFromForm = ( | ||
| startDate: string, | ||
| startDateTime: string, | ||
| endDate: string, | ||
| endDateTime: string | ||
| ) => { | ||
| const start = `${startDate} ${startDateTime}`; | ||
| const end = `${endDate} ${endDateTime}`; | ||
| return { | ||
| start: `${moment(start, 'YYYY-MM-DD HH:mm').valueOf()}000`, | ||
| end: `${moment(end, 'YYYY-MM-DD HH:mm').valueOf()}000` | ||
| }; | ||
| }; | ||
|
|
||
| export const JaegerThunkActions = { | ||
| asyncFetchServices: (ns: string) => { | ||
| return (dispatch: ThunkDispatch<KialiAppState, void, KialiAppAction>, getState: () => KialiAppState) => { | ||
| if (getState()['authentication']['token'] === undefined) { | ||
| return Promise.resolve(); | ||
| } | ||
| /** Get the token storage in redux-store */ | ||
| const token = getState().authentication.token!.token; | ||
| /** generate Token */ | ||
| const auth = `Bearer ${token}`; | ||
|
|
||
| // Dispatch a thunk from thunk! | ||
| dispatch(JaegerActions.requestStarted()); | ||
| return Api.getServices(auth, ns) | ||
| .then(response => response['data']) | ||
| .then(data => { | ||
| const serviceList: string[] = []; | ||
| data['services'].forEach((aService: ServiceOverview) => { | ||
| serviceList.push(aService.name); | ||
| }); | ||
| dispatch(JaegerActions.receiveList(serviceList)); | ||
| }) | ||
| .catch(() => dispatch(JaegerActions.requestFailed())); | ||
| }; | ||
| }, | ||
| getSearchURL: () => { | ||
| return (dispatch: ThunkDispatch<KialiAppState, void, KialiAppAction>, getState: () => KialiAppState) => { | ||
| const searchOptions = getState().jaegerState.search; | ||
| const jaegerOptions = JAEGER_QUERY().OPTIONS; | ||
| const urlRequest = new JaegerURLSearch(getState().jaegerState.jaegerURL); | ||
|
|
||
| // Search options | ||
| urlRequest.addQueryParam(jaegerOptions.START_TIME, searchOptions.start); | ||
| urlRequest.addQueryParam(jaegerOptions.END_TIME, searchOptions.end); | ||
| urlRequest.addQueryParam(jaegerOptions.LIMIT_TRACES, searchOptions.limit); | ||
| urlRequest.addQueryParam(jaegerOptions.LOOKBACK, searchOptions.lookback); | ||
| urlRequest.addQueryParam(jaegerOptions.MAX_DURATION, searchOptions.maxDuration); | ||
| urlRequest.addQueryParam(jaegerOptions.MIN_DURATION, searchOptions.minDuration); | ||
| urlRequest.addQueryParam( | ||
| jaegerOptions.SERVICE_SELECTOR, | ||
| searchOptions.serviceSelected + '.' + searchOptions.namespaceSelected | ||
| ); | ||
| const logfmtTags = convTagsLogfmt(searchOptions.tags); | ||
| if (logfmtTags) { | ||
| urlRequest.addQueryParam(jaegerOptions.TAGS, logfmtTags); | ||
| } | ||
|
|
||
| // Embed Options | ||
| const traceOptions = getState().jaegerState.trace; | ||
|
|
||
| // Rename query params for 1.9 Jaeger | ||
| urlRequest.addQueryParam(JAEGER_QUERY().EMBED.UI_TRACE_HIDE_MINIMAP, traceOptions.hideMinimap ? '1' : '0'); | ||
| urlRequest.addQueryParam(JAEGER_QUERY().EMBED.UI_SEARCH_HIDE_GRAPH, searchOptions.hideGraph ? '1' : '0'); | ||
| urlRequest.addQueryParam(JAEGER_QUERY().EMBED.UI_TRACE_HIDE_SUMMARY, traceOptions.hideSummary ? '1' : '0'); | ||
|
|
||
| return dispatch(JaegerActions.setSearchRequest(urlRequest.url)); | ||
| }; | ||
| }, | ||
| setCustomLookback: (startDate: string, startTime: string, endDate: string, endTime: string) => { | ||
| return (dispatch: ThunkDispatch<KialiAppState, void, KialiAppAction>, getState: () => KialiAppState) => { | ||
| if (getState().jaegerState.search.lookback === 'custom') { | ||
| const toTimestamp = getUnixTimeStampInMSFromForm(startDate, startTime, endDate, endTime); | ||
| dispatch(JaegerActions.setCustomLookback(toTimestamp.start, toTimestamp.end)); | ||
| } | ||
| }; | ||
| } | ||
| }; |
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,43 @@ | ||
| import { JaegerActions } from '../JaegerActions'; | ||
| import { getType } from 'typesafe-actions'; | ||
|
|
||
| describe('JaegerActions', () => { | ||
| it('should "update url" action', () => { | ||
| const showAction = JaegerActions.setUrl('jaeger-query-istio-system.127.0.0.1.nip.io'); | ||
| expect(showAction.type).toEqual(getType(JaegerActions.setUrl)); | ||
| expect(showAction.payload).toEqual({ | ||
| url: 'jaeger-query-istio-system.127.0.0.1.nip.io' | ||
| }); | ||
| }); | ||
|
|
||
| it('should "receive list of services" action', () => { | ||
| const services = ['details', 'productpage']; | ||
| const showAction = JaegerActions.receiveList(services); | ||
| expect(showAction.type).toEqual(getType(JaegerActions.receiveList)); | ||
| expect(showAction.payload).toEqual({ | ||
| list: services | ||
| }); | ||
| }); | ||
|
|
||
| it('should "update custom lookback" action', () => { | ||
| const start = '1544432675600000'; | ||
| const end = '1544432625600000'; | ||
| const showAction = JaegerActions.setCustomLookback(start, end); | ||
| expect(showAction.type).toEqual(getType(JaegerActions.setCustomLookback)); | ||
| expect(showAction.payload).toEqual({ | ||
| start: start, | ||
| end: end | ||
| }); | ||
| }); | ||
|
|
||
| it('should "update durations" action', () => { | ||
| const min = '10ms'; | ||
| const max = '10s'; | ||
| const showAction = JaegerActions.setDurations(min, max); | ||
| expect(showAction.type).toEqual(getType(JaegerActions.setDurations)); | ||
| expect(showAction.payload).toEqual({ | ||
| min: min, | ||
| max: max | ||
| }); | ||
| }); | ||
| }); |
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,70 @@ | ||
| import { convTagsLogfmt, getUnixTimeStampInMSFromForm, JaegerURLSearch } from '../JaegerThunkActions'; | ||
| import { JAEGER_QUERY } from '../../config'; | ||
| import moment from 'moment-timezone'; | ||
|
|
||
| describe('JaegerThunkActions', () => { | ||
| describe('Methods & Class', () => { | ||
| describe('Method convTagsLogfmt', () => { | ||
| it('convTagsLogfmt should return null if tags is empty', () => { | ||
| expect(convTagsLogfmt('')).toEqual(null); | ||
| }); | ||
|
|
||
| it('convTagsLogfmt should JSON stringify of the tags', () => { | ||
| expect(convTagsLogfmt('error=true')).toEqual('{"error":"true"}'); | ||
|
|
||
| expect(convTagsLogfmt('http.status_code=200 error=true')).toEqual('{"http.status_code":"200","error":"true"}'); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Method getUnixTimeStampInMSFromForm', () => { | ||
| it('getUnixTimeStampInMSFromForm should return the correct start and end time in MS', () => { | ||
| moment.tz.setDefault('UTC'); | ||
| const date = '2019-01-01'; | ||
| const startTime = '10:30'; | ||
| const endTime = '11:30'; | ||
| const result = getUnixTimeStampInMSFromForm(date, startTime, date, endTime); | ||
| expect(result.start).toEqual('1546338600000000'); | ||
| expect(result.end).toEqual('1546342200000000'); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Class JaegerURLSearch', () => { | ||
| const url = 'https://jaeger-query-istio-system.127.0.0.1.nip.io'; | ||
| let jaegerURLclass; | ||
|
|
||
| beforeEach(() => { | ||
| jaegerURLclass = new JaegerURLSearch(url); | ||
| }); | ||
|
|
||
| it('JaegerURLSearch constructor', () => { | ||
| expect(jaegerURLclass.url).toEqual( | ||
| `${url}${JAEGER_QUERY().PATH}?${JAEGER_QUERY().EMBED.UI_EMBED}=${JAEGER_QUERY().EMBED.VERSION}` | ||
| ); | ||
| }); | ||
|
|
||
| it('JaegerURLSearch addQueryParam method with number value', () => { | ||
| jaegerURLclass.addQueryParam('uiTimelineHideMinimap', 1); | ||
| expect(jaegerURLclass.url).toEqual( | ||
| `${url}${JAEGER_QUERY().PATH}?${JAEGER_QUERY().EMBED.UI_EMBED}=${ | ||
| JAEGER_QUERY().EMBED.VERSION | ||
| }&uiTimelineHideMinimap=1` | ||
| ); | ||
| jaegerURLclass.addQueryParam('uiTimelineHideSummary', '0'); | ||
| expect(jaegerURLclass.url).toEqual( | ||
| `${url}${JAEGER_QUERY().PATH}?${JAEGER_QUERY().EMBED.UI_EMBED}=${ | ||
| JAEGER_QUERY().EMBED.VERSION | ||
| }&uiTimelineHideMinimap=1&uiTimelineHideSummary=0` | ||
| ); | ||
| }); | ||
|
|
||
| it('JaegerURLSearch addParam method', () => { | ||
| jaegerURLclass.addParam('uiTimelineHideMinimap'); | ||
| expect(jaegerURLclass.url).toEqual( | ||
| `${url}${JAEGER_QUERY().PATH}?${JAEGER_QUERY().EMBED.UI_EMBED}=${ | ||
| JAEGER_QUERY().EMBED.VERSION | ||
| }&uiTimelineHideMinimap` | ||
| ); | ||
| }); | ||
| }); | ||
| }); | ||
| }); |
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
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you provide some information on how and why this library is used? If I understand correctly it's also used in jaeger, but I'm not sure if we really need it, what I can see is that
searchOptions.tagsis expected to be a string in "logfmt" format and then is converted to plain json string to pass to jaeger, but what I fail to see is where these tags come from and if we can avoid having them in that format in the first place.Also, I think you should remove the caret in lib version, as we don't use it in general.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logfmt is used in src/actions/JaegerThunkActions.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aljesusg can you also fix that in your new PR? (the caret version)