* change(ui) - redirect to the landing url on SSO login
* fix(ui): fix share popup styles
* change(ui) - non admin user preference restrictions
* fix(ui) - redirect fix
* change(ui) - show installation btn without mouse hover
* feat(api): api-v1 handle wrong projectKey
feat(api): api-v1 get live sessions
* change(ui) - show role edit on hover
* change(ui) - audit trail count with comma
* fix(ui) - audit trail date range custom picker alignment
* change(ui) - show a message when mob file not found
* feat(api): api-v1 fixed search live sessions
* feat(api): api-v1 handle wrong projectKey
* feat(api): fixed assist error response
* fix(tracker): check node scrolls only on start
* fixup! fix(tracker): check node scrolls only on start
* feat(ui/player): scroll view in click map
* feat(ui/player): rm unused check
* New configuration module (#558)
* ci(dbmigrate): Create db migrate when there is change
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(ui): fix login error/button margins
* fix(ui) - checkbox click
* fix(ui) - search rename and save fixes
* change(ui) - text changes
* fix(ui) - button text nowrap
* fix(ui): fix slowestdomains widget height
* change(ui) - ignore clicks while annotating
* change(ui) - if block with braces
* change(ui) - capitalize first letter in breadcrumb
* feat(db): remove errors from permissions
feat(api): remove errors from permissions
* feat(api): changed reset password response
* fix(ui) - assist active tab list, broken after with new api changes (pagination)
* fix(ui) - assist active tab list, broken after with new api changes (pagination)
* change(ui) - search compare
* fix(ui): last fixes for 1.7
* fix(ui): fix timeline
* fix(ui): small code fixes
* fix(ui): remove unused
* feat(frontend/assist): show when client tab is inactive + fix reconnection status update
* fix(ui) - visibility settings
* feat(assist): refactored extractSessionInfo
feat(assist): hardcoded session's attributes
* Added snabbdom (JS)
* fix(tracker): version check works with x.x.x-beta versions
* fix(backend): keep the highest user's timestamp instead of the latest message timestamp for correct session duration value
* feat(backend/s3): added file tag RETENTION (#561)
* change(ui) - search optimization and autocomplete improvements
* feat(backend/assets): added new metrics assets_downloaded
* change(ui) - show back the date range in bookmarks since the api is filtering by daterange
* feat(backend-assets): custom headers for cacher requests
* chore(backend): no tidy in dockerfile (local build speed up)
* feat(backend/assets): added proxy support for cacher module
* feat(backend/storage): set retention env variable as not required
* fix(ui): fix jira issues
* ci(helm): use kubectl for deployment
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* feat(tracker):3.5.13: performance improvements for a case of extensive dom
* fix(backend): added missed err var and continue statement
* ci(helm): forcing namespace
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* feat(api): fixed slowest_domains query
* ci(helm): update helm deployment method
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* change(ui) - filter dropdown colros
* fix(ui) - speed index location avg attribute changed to value
* ci(api): enable kubectl apply
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(ui) - widget y axis label
* feat(api): fixed slowest_domains query
* chore(helm): Adding namespaces to all templates (#565)
* feat(api): assist type-autocomplete
* feat(api): assist global-autocomplete
* feat(sourcemaps): include wasm file in build
* feat(sourcemaps-reader): refactored
* fix(ui): fix data for funnels
* fix(ui): fix all sessions section margin
* fix(ui) - assist loader flag
* fix(ui) - assist loader flag
* fix(ui): fix weird check
* feat(api): autocomplete accept unsupported types
* feat(ui): migrate to yarn v3
* feat(ui): minor fixes for installment
* feat(ui): add typescript plugin to yarn
* chore(helm): Ability to override image registry
* chore(helm): Overriding openreplay docker registry
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(ui): fix control arrows on firefox
* feat(crons): EE crons
* feat(api): fixed build script
* feat(alerts): fixed build script
* feat(crons): fixed build script
* chore(helm): Updating cron version
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* feat(crons): changes
* chore(helm): optional minio ingress
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* feat(crons): fix build script
feat(alerts): fix build script
* Revert "chore(helm): Updating cron version"
This reverts commit 3ca190ea2f.
* feat(crons): fix build script
* feat(crons): fix Dockerfile
* feat(api): fixed metadata change-case
* change(ui) - remove capitalize for the meta value
* change(ui) - autocomplete improvements with custom textfield
* fix(tracker):3.5.13+:reuse metadata on internal-caused restarts
* fix(tracker-assist):3.5.13:send active:true on start; scroll behavior fix
* change(ui) - filters autocomplete blur on pressing Enter key
* fix(tracker): fix node v to lower
* fix(tracker): fix deps
* fix(tracker): fix deps
* fix(ui) - dashboard modal width
* change(ui) - filter dropdown overflow
* chore(helm): clickhouse reclaim polity to retain
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(tracker): fix engine max v
* fix(ui): load metadata in assist tab for sorting
* fix(ui): rm unneeded api call
* fix(tracker): build script to cjs
* change(ui) - removed sample data
* chore(tracker): remove upper node version limit
* Updating Beacon size
Beacon size should be <= QUEUE_MESSAGE_SIZE_LIMIT
* feat(crons): run 24/7
feat(alerts): support env-file override
* feat(api): changed EE env handler
* fix(ui): fix sessions search modal
* change(ui) - margin for error message
* change(ui) - disable assist sort when there are no meta options to choose
* chore(helm): Adding utilities service namespace
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(ui) - dashboard date range selection reload, metric not found message
* change(ui) - disable clearsearch in assist when there are no filters\
* feat(api): fixed EE env handler
* chore(helm): Adding migration namespaces
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(ui) - report logo path
* chore(helm): Removing unnecessary SA
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* feat(api): changed EE env handler
* feat(api): changed EE env handler
* feat(api): changed EE env handler
* feat(api): changed EE env handler
* feat(crons): changed crons
* feat(api): accept wrong metric_id
* feat(crons): changed env handler
feat(api): changed env handler
feat(alerts): changed env handler
* feat(utilities): support old version of nodejs
* feat(crons): changed env handler
feat(api): changed env handler
feat(alerts): changed env handler
* fix(tracker): fix srcset tracking
* chore(build): Adding frontent
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* feat(assist): changed general helper
* feat(assist): changed general helper
* fix(ui): fix widget pagination (#570)
* feat(crons): changed entrypoint
* feat(player): dev-log on skipping message
* fix(tracker): removeNode mutation priority over attributes
* fix(tracker): capture relative img timing;use startsWith instead of substr; codestyle fix
* chore(build): fixing api build script
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* chore(ci): faster deployment
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* change(ui) - assist list show active status
* chore(actions): option to build all/specific services in GH
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(ui) - slowest domain metric data as per the api changes
* ci(helm): updated variable name
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* ci(backend): cherrypick changes to ee
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* feat(backend): disabled pprof in http service
* fix(ui) - TimeToRender avg value as per the API change
* fix(ui) - ResponseTimeDistribution avg value as per the API change
* fix(ui) - MemoryConsumption avg value as per the API change
* fix(ui) - ResponseTime avg value as per the API change
* fix(ui) - DomBuildTime avg value as per the API change
* fix(ui) - FrameRate avg value as per the API change
* chore(helm): proper default tag
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* feat(backend): removed sensitive information from http logs
* ci(backend): adding default parameter value for workflow dispatch
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(backend): deleted empty file
* fix(actions): creating image source file prior
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(helm): variable substitution
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* change(ui) - project list item installation button text change
* fix(ui) - project create validation
* fix(backend): removed unsafe string logs in http service
* chore(kafka): Adding new topic
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(efs-cron): variable name
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(ui) - developer tools - hint links
* fix(ui) - session filters - country and platform dropdown values
* chore(helm): updating version
* chore(kafka): Update kafka default message size while provisioning
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(tracker): fix dependency security
* change(ui) - webhook delete confirmation
* change(ui) - assist url to handle when empty
* feat(api): autocomplete replace console with errors
feat(DB): clean extra files
* chore(helm): Adding cron jobs
* change(ui) - set changed flag to false after the metric delete to avoid prompt
* chore(helm): enbaling cron only for ee
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* feat(api): autocomplete remove console
* change(ui) - removed Console filter type
* fix(ui) - timeline position
* fix(helm): RFC naming
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(ui): let user change project in dashboards and select default dashboard
* chore(helm): update registry url
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* feat(DB): return pages_count to DB
* fix(ui) - account settings opt out checkbox
* fix(ui): fix modal width
* fix(ui) - explore circle bg
* fix(ui) - user name overlap
* fix(ui) - empty dashboards create button
* fix(ui): fix timeline position cursor for safari
* fix(ui) - custom metrics errors modal url reset on close
* fix(ui) - onboarding check for siteId
* change(ui) - tracker version
* Update local_deploy.sh
* fix(ui) - drilldown timestamp
* fix(tracker): fix deps for assist
* fix(tracker): update peerjs library
* fix(tracker): update assist v
* fix(tracker): fix type error
* fix(backend): no missing resource relying on resource zero-timing
* Update tracker to v3.5.15
* chore(helm): Adding CSP override variable.
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* feat(backend): added pem file support for kafka ssl setup
* feat(backend): added useBatch setup for kafka producer
* ci(backend): set verbose logging
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(backend): using setKey instead of direct writes
* ci(backend): fix error code
* ci(deploy): Updating the image registry
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* feat(api): changed get user id alias
* ci(frontent): removing depricated steps
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* ci(fix): variable replace
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* ci(helm): creating image image_override
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
* fix(ui): fix timezone settings
* Added failover mechanism for storage service (#576)
* fix(ui): fix typescript config to remove array iterator error
* fix(ui): refactor timezone settings store/comp
* feat(snippet): opensource snippet
* feat(assist): support multiple IPs
* fix(ui): fix type errors in select /timezones fix
* feat(backend): set size of first part of sessions at 500kb
* change(ui) - removed logs
* fix(ui) - custom metric errors reset url on modal close
* feat(DB): no funnel migration
* fix(ui): fix screensize bug
* feat(DB): migrate super old funnels support
* changed db-migration workflow
Co-authored-by: Shekar Siri <sshekarsiri@gmail.com>
Co-authored-by: sylenien <nikita@openreplay.com>
Co-authored-by: Alex Kaminskii <alex@openreplay.com>
Co-authored-by: Alexander <zavorotynskiy@pm.me>
Co-authored-by: rjshrjndrn <rjshrjndrn@gmail.com>
Co-authored-by: Mehdi Osman <estradino@users.noreply.github.com>
Co-authored-by: Alexander <alexander@openreplay.com>
Co-authored-by: Rajesh Rajendran <rjshrjndrn@users.noreply.github.com>
Co-authored-by: Delirium <sylenien@gmail.com>
485 lines
25 KiB
Python
485 lines
25 KiB
Python
import schemas
|
|
from chalicelib.core import issues
|
|
from chalicelib.core import sessions_metas, metadata
|
|
from chalicelib.utils import pg_client, helper
|
|
from chalicelib.utils.TimeUTC import TimeUTC
|
|
from chalicelib.utils.event_filter_definition import SupportedFilter, Event
|
|
|
|
|
|
def get_customs_by_sessionId2_pg(session_id, project_id):
|
|
with pg_client.PostgresClient() as cur:
|
|
cur.execute(cur.mogrify("""\
|
|
SELECT
|
|
c.*,
|
|
'CUSTOM' AS type
|
|
FROM events_common.customs AS c
|
|
WHERE
|
|
c.session_id = %(session_id)s
|
|
ORDER BY c.timestamp;""",
|
|
{"project_id": project_id, "session_id": session_id})
|
|
)
|
|
rows = cur.fetchall()
|
|
return helper.dict_to_camel_case(rows)
|
|
|
|
|
|
def __merge_cells(rows, start, count, replacement):
|
|
rows[start] = replacement
|
|
rows = rows[:start + 1] + rows[start + count:]
|
|
return rows
|
|
|
|
|
|
def __get_grouped_clickrage(rows, session_id, project_id):
|
|
click_rage_issues = issues.get_by_session_id(session_id=session_id, issue_type="click_rage", project_id=project_id)
|
|
if len(click_rage_issues) == 0:
|
|
return rows
|
|
|
|
for c in click_rage_issues:
|
|
merge_count = c.get("payload")
|
|
if merge_count is not None:
|
|
merge_count = merge_count.get("count", 3)
|
|
else:
|
|
merge_count = 3
|
|
for i in range(len(rows)):
|
|
if rows[i]["timestamp"] == c["timestamp"]:
|
|
rows = __merge_cells(rows=rows,
|
|
start=i,
|
|
count=merge_count,
|
|
replacement={**rows[i], "type": "CLICKRAGE", "count": merge_count})
|
|
break
|
|
return rows
|
|
|
|
|
|
def get_by_sessionId2_pg(session_id, project_id, group_clickrage=False):
|
|
with pg_client.PostgresClient() as cur:
|
|
cur.execute(cur.mogrify("""\
|
|
SELECT
|
|
c.*,
|
|
'CLICK' AS type
|
|
FROM events.clicks AS c
|
|
WHERE
|
|
c.session_id = %(session_id)s
|
|
ORDER BY c.timestamp;""",
|
|
{"project_id": project_id, "session_id": session_id})
|
|
)
|
|
rows = cur.fetchall()
|
|
if group_clickrage:
|
|
rows = __get_grouped_clickrage(rows=rows, session_id=session_id, project_id=project_id)
|
|
|
|
cur.execute(cur.mogrify("""
|
|
SELECT
|
|
i.*,
|
|
'INPUT' AS type
|
|
FROM events.inputs AS i
|
|
WHERE
|
|
i.session_id = %(session_id)s
|
|
ORDER BY i.timestamp;""",
|
|
{"project_id": project_id, "session_id": session_id})
|
|
)
|
|
rows += cur.fetchall()
|
|
cur.execute(cur.mogrify("""\
|
|
SELECT
|
|
l.*,
|
|
l.path AS value,
|
|
l.path AS url,
|
|
'LOCATION' AS type
|
|
FROM events.pages AS l
|
|
WHERE
|
|
l.session_id = %(session_id)s
|
|
ORDER BY l.timestamp;""", {"project_id": project_id, "session_id": session_id}))
|
|
rows += cur.fetchall()
|
|
rows = helper.list_to_camel_case(rows)
|
|
rows = sorted(rows, key=lambda k: (k["timestamp"], k["messageId"]))
|
|
return rows
|
|
|
|
|
|
def __get_data_for_extend(data):
|
|
if "errors" not in data:
|
|
return data["data"]
|
|
|
|
|
|
def __pg_errors_query(source=None, value_length=None):
|
|
if value_length is None or value_length > 2:
|
|
return f"""((SELECT DISTINCT ON(lg.message)
|
|
lg.message AS value,
|
|
source,
|
|
'{event_type.ERROR.ui_type}' AS type
|
|
FROM {event_type.ERROR.table} INNER JOIN public.errors AS lg USING (error_id) LEFT JOIN public.sessions AS s USING(session_id)
|
|
WHERE
|
|
s.project_id = %(project_id)s
|
|
AND lg.message ILIKE %(svalue)s
|
|
AND lg.project_id = %(project_id)s
|
|
{"AND source = %(source)s" if source is not None else ""}
|
|
LIMIT 5)
|
|
UNION ALL
|
|
(SELECT DISTINCT ON(lg.name)
|
|
lg.name AS value,
|
|
source,
|
|
'{event_type.ERROR.ui_type}' AS type
|
|
FROM {event_type.ERROR.table} INNER JOIN public.errors AS lg USING (error_id) LEFT JOIN public.sessions AS s USING(session_id)
|
|
WHERE
|
|
s.project_id = %(project_id)s
|
|
AND lg.name ILIKE %(svalue)s
|
|
AND lg.project_id = %(project_id)s
|
|
{"AND source = %(source)s" if source is not None else ""}
|
|
LIMIT 5)
|
|
UNION
|
|
(SELECT DISTINCT ON(lg.message)
|
|
lg.message AS value,
|
|
source,
|
|
'{event_type.ERROR.ui_type}' AS type
|
|
FROM {event_type.ERROR.table} INNER JOIN public.errors AS lg USING (error_id) LEFT JOIN public.sessions AS s USING(session_id)
|
|
WHERE
|
|
s.project_id = %(project_id)s
|
|
AND lg.message ILIKE %(value)s
|
|
AND lg.project_id = %(project_id)s
|
|
{"AND source = %(source)s" if source is not None else ""}
|
|
LIMIT 5)
|
|
UNION ALL
|
|
(SELECT DISTINCT ON(lg.name)
|
|
lg.name AS value,
|
|
source,
|
|
'{event_type.ERROR.ui_type}' AS type
|
|
FROM {event_type.ERROR.table} INNER JOIN public.errors AS lg USING (error_id) LEFT JOIN public.sessions AS s USING(session_id)
|
|
WHERE
|
|
s.project_id = %(project_id)s
|
|
AND lg.name ILIKE %(value)s
|
|
AND lg.project_id = %(project_id)s
|
|
{"AND source = %(source)s" if source is not None else ""}
|
|
LIMIT 5));"""
|
|
return f"""((SELECT DISTINCT ON(lg.message)
|
|
lg.message AS value,
|
|
source,
|
|
'{event_type.ERROR.ui_type}' AS type
|
|
FROM {event_type.ERROR.table} INNER JOIN public.errors AS lg USING (error_id) LEFT JOIN public.sessions AS s USING(session_id)
|
|
WHERE
|
|
s.project_id = %(project_id)s
|
|
AND lg.message ILIKE %(svalue)s
|
|
AND lg.project_id = %(project_id)s
|
|
{"AND source = %(source)s" if source is not None else ""}
|
|
LIMIT 5)
|
|
UNION ALL
|
|
(SELECT DISTINCT ON(lg.name)
|
|
lg.name AS value,
|
|
source,
|
|
'{event_type.ERROR.ui_type}' AS type
|
|
FROM {event_type.ERROR.table} INNER JOIN public.errors AS lg USING (error_id) LEFT JOIN public.sessions AS s USING(session_id)
|
|
WHERE
|
|
s.project_id = %(project_id)s
|
|
AND lg.name ILIKE %(svalue)s
|
|
AND lg.project_id = %(project_id)s
|
|
{"AND source = %(source)s" if source is not None else ""}
|
|
LIMIT 5));"""
|
|
|
|
|
|
def __search_pg_errors(project_id, value, key=None, source=None):
|
|
now = TimeUTC.now()
|
|
|
|
with pg_client.PostgresClient() as cur:
|
|
cur.execute(
|
|
cur.mogrify(__pg_errors_query(source,
|
|
value_length=len(value) \
|
|
if SUPPORTED_TYPES[event_type.ERROR.ui_type].change_by_length else None),
|
|
{"project_id": project_id, "value": helper.string_to_sql_like(value),
|
|
"svalue": helper.string_to_sql_like("^" + value),
|
|
"source": source}))
|
|
results = helper.list_to_camel_case(cur.fetchall())
|
|
print(f"{TimeUTC.now() - now} : errors")
|
|
return results
|
|
|
|
|
|
def __search_pg_errors_ios(project_id, value, key=None, source=None):
|
|
now = TimeUTC.now()
|
|
if SUPPORTED_TYPES[event_type.ERROR_IOS.ui_type].change_by_length is False or len(value) > 2:
|
|
query = f"""(SELECT DISTINCT ON(lg.reason)
|
|
lg.reason AS value,
|
|
'{event_type.ERROR_IOS.ui_type}' AS type
|
|
FROM {event_type.ERROR_IOS.table} INNER JOIN public.crashes_ios AS lg USING (crash_id) LEFT JOIN public.sessions AS s USING(session_id)
|
|
WHERE
|
|
s.project_id = %(project_id)s
|
|
AND lg.project_id = %(project_id)s
|
|
AND lg.reason ILIKE %(svalue)s
|
|
LIMIT 5)
|
|
UNION ALL
|
|
(SELECT DISTINCT ON(lg.name)
|
|
lg.name AS value,
|
|
'{event_type.ERROR_IOS.ui_type}' AS type
|
|
FROM {event_type.ERROR_IOS.table} INNER JOIN public.crashes_ios AS lg USING (crash_id) LEFT JOIN public.sessions AS s USING(session_id)
|
|
WHERE
|
|
s.project_id = %(project_id)s
|
|
AND lg.project_id = %(project_id)s
|
|
AND lg.name ILIKE %(svalue)s
|
|
LIMIT 5)
|
|
UNION ALL
|
|
(SELECT DISTINCT ON(lg.reason)
|
|
lg.reason AS value,
|
|
'{event_type.ERROR_IOS.ui_type}' AS type
|
|
FROM {event_type.ERROR_IOS.table} INNER JOIN public.crashes_ios AS lg USING (crash_id) LEFT JOIN public.sessions AS s USING(session_id)
|
|
WHERE
|
|
s.project_id = %(project_id)s
|
|
AND lg.project_id = %(project_id)s
|
|
AND lg.reason ILIKE %(value)s
|
|
LIMIT 5)
|
|
UNION ALL
|
|
(SELECT DISTINCT ON(lg.name)
|
|
lg.name AS value,
|
|
'{event_type.ERROR_IOS.ui_type}' AS type
|
|
FROM {event_type.ERROR_IOS.table} INNER JOIN public.crashes_ios AS lg USING (crash_id) LEFT JOIN public.sessions AS s USING(session_id)
|
|
WHERE
|
|
s.project_id = %(project_id)s
|
|
AND lg.project_id = %(project_id)s
|
|
AND lg.name ILIKE %(value)s
|
|
LIMIT 5);"""
|
|
else:
|
|
query = f"""(SELECT DISTINCT ON(lg.reason)
|
|
lg.reason AS value,
|
|
'{event_type.ERROR_IOS.ui_type}' AS type
|
|
FROM {event_type.ERROR_IOS.table} INNER JOIN public.crashes_ios AS lg USING (crash_id) LEFT JOIN public.sessions AS s USING(session_id)
|
|
WHERE
|
|
s.project_id = %(project_id)s
|
|
AND lg.project_id = %(project_id)s
|
|
AND lg.reason ILIKE %(svalue)s
|
|
LIMIT 5)
|
|
UNION ALL
|
|
(SELECT DISTINCT ON(lg.name)
|
|
lg.name AS value,
|
|
'{event_type.ERROR_IOS.ui_type}' AS type
|
|
FROM {event_type.ERROR_IOS.table} INNER JOIN public.crashes_ios AS lg USING (crash_id) LEFT JOIN public.sessions AS s USING(session_id)
|
|
WHERE
|
|
s.project_id = %(project_id)s
|
|
AND lg.project_id = %(project_id)s
|
|
AND lg.name ILIKE %(svalue)s
|
|
LIMIT 5);"""
|
|
with pg_client.PostgresClient() as cur:
|
|
cur.execute(cur.mogrify(query, {"project_id": project_id, "value": helper.string_to_sql_like(value),
|
|
"svalue": helper.string_to_sql_like("^" + value)}))
|
|
results = helper.list_to_camel_case(cur.fetchall())
|
|
print(f"{TimeUTC.now() - now} : errors")
|
|
return results
|
|
|
|
|
|
def __search_pg_metadata(project_id, value, key=None, source=None):
|
|
meta_keys = metadata.get(project_id=project_id)
|
|
meta_keys = {m["key"]: m["index"] for m in meta_keys}
|
|
if len(meta_keys) == 0 or key is not None and key not in meta_keys.keys():
|
|
return []
|
|
sub_from = []
|
|
if key is not None:
|
|
meta_keys = {key: meta_keys[key]}
|
|
|
|
for k in meta_keys.keys():
|
|
colname = metadata.index_to_colname(meta_keys[k])
|
|
if SUPPORTED_TYPES[event_type.METADATA.ui_type].change_by_length is False or len(value) > 2:
|
|
sub_from.append(f"""((SELECT DISTINCT ON ({colname}) {colname} AS value, '{k}' AS key
|
|
FROM public.sessions
|
|
WHERE project_id = %(project_id)s
|
|
AND {colname} ILIKE %(svalue)s LIMIT 5)
|
|
UNION
|
|
(SELECT DISTINCT ON ({colname}) {colname} AS value, '{k}' AS key
|
|
FROM public.sessions
|
|
WHERE project_id = %(project_id)s
|
|
AND {colname} ILIKE %(value)s LIMIT 5))
|
|
""")
|
|
else:
|
|
sub_from.append(f"""(SELECT DISTINCT ON ({colname}) {colname} AS value, '{k}' AS key
|
|
FROM public.sessions
|
|
WHERE project_id = %(project_id)s
|
|
AND {colname} ILIKE %(svalue)s LIMIT 5)""")
|
|
with pg_client.PostgresClient() as cur:
|
|
cur.execute(cur.mogrify(f"""\
|
|
SELECT key, value, 'METADATA' AS TYPE
|
|
FROM({" UNION ALL ".join(sub_from)}) AS all_metas
|
|
LIMIT 5;""", {"project_id": project_id, "value": helper.string_to_sql_like(value),
|
|
"svalue": helper.string_to_sql_like("^" + value)}))
|
|
results = helper.list_to_camel_case(cur.fetchall())
|
|
return results
|
|
|
|
|
|
def __generic_query(typename, value_length=None):
|
|
if value_length is None or value_length > 2:
|
|
return f"""(SELECT DISTINCT value, type
|
|
FROM public.autocomplete
|
|
WHERE
|
|
project_id = %(project_id)s
|
|
AND type='{typename}'
|
|
AND value ILIKE %(svalue)s
|
|
LIMIT 5)
|
|
UNION
|
|
(SELECT DISTINCT value, type
|
|
FROM public.autocomplete
|
|
WHERE
|
|
project_id = %(project_id)s
|
|
AND type='{typename}'
|
|
AND value ILIKE %(value)s
|
|
LIMIT 5);"""
|
|
return f"""SELECT DISTINCT value, type
|
|
FROM public.autocomplete
|
|
WHERE
|
|
project_id = %(project_id)s
|
|
AND type='{typename}'
|
|
AND value ILIKE %(svalue)s
|
|
LIMIT 10;"""
|
|
|
|
|
|
def __generic_autocomplete(event: Event):
|
|
def f(project_id, value, key=None, source=None):
|
|
with pg_client.PostgresClient() as cur:
|
|
cur.execute(
|
|
cur.mogrify(
|
|
__generic_query(event.ui_type,
|
|
value_length=len(value) \
|
|
if SUPPORTED_TYPES[event.ui_type].change_by_length \
|
|
else None),
|
|
{"project_id": project_id, "value": helper.string_to_sql_like(value),
|
|
"svalue": helper.string_to_sql_like("^" + value)}))
|
|
return helper.list_to_camel_case(cur.fetchall())
|
|
|
|
return f
|
|
|
|
|
|
class event_type:
|
|
CLICK = Event(ui_type=schemas.EventType.click, table="events.clicks", column="label")
|
|
INPUT = Event(ui_type=schemas.EventType.input, table="events.inputs", column="label")
|
|
LOCATION = Event(ui_type=schemas.EventType.location, table="events.pages", column="path")
|
|
CUSTOM = Event(ui_type=schemas.EventType.custom, table="events_common.customs", column="name")
|
|
REQUEST = Event(ui_type=schemas.EventType.request, table="events_common.requests", column="path")
|
|
GRAPHQL = Event(ui_type=schemas.EventType.graphql, table="events.graphql", column="name")
|
|
STATEACTION = Event(ui_type=schemas.EventType.state_action, table="events.state_actions", column="name")
|
|
ERROR = Event(ui_type=schemas.EventType.error, table="events.errors",
|
|
column=None) # column=None because errors are searched by name or message
|
|
METADATA = Event(ui_type=schemas.FilterType.metadata, table="public.sessions", column=None)
|
|
# IOS
|
|
CLICK_IOS = Event(ui_type=schemas.EventType.click_ios, table="events_ios.clicks", column="label")
|
|
INPUT_IOS = Event(ui_type=schemas.EventType.input_ios, table="events_ios.inputs", column="label")
|
|
VIEW_IOS = Event(ui_type=schemas.EventType.view_ios, table="events_ios.views", column="name")
|
|
CUSTOM_IOS = Event(ui_type=schemas.EventType.custom_ios, table="events_common.customs", column="name")
|
|
REQUEST_IOS = Event(ui_type=schemas.EventType.request_ios, table="events_common.requests", column="url")
|
|
ERROR_IOS = Event(ui_type=schemas.EventType.error_ios, table="events_ios.crashes",
|
|
column=None) # column=None because errors are searched by name or message
|
|
|
|
|
|
SUPPORTED_TYPES = {
|
|
event_type.CLICK.ui_type: SupportedFilter(get=__generic_autocomplete(event_type.CLICK),
|
|
query=__generic_query(typename=event_type.CLICK.ui_type),
|
|
change_by_length=True),
|
|
event_type.INPUT.ui_type: SupportedFilter(get=__generic_autocomplete(event_type.INPUT),
|
|
query=__generic_query(typename=event_type.INPUT.ui_type),
|
|
change_by_length=True),
|
|
event_type.LOCATION.ui_type: SupportedFilter(get=__generic_autocomplete(event_type.LOCATION),
|
|
query=__generic_query(typename=event_type.LOCATION.ui_type),
|
|
change_by_length=True),
|
|
event_type.CUSTOM.ui_type: SupportedFilter(get=__generic_autocomplete(event_type.CUSTOM),
|
|
query=__generic_query(typename=event_type.CUSTOM.ui_type),
|
|
change_by_length=True),
|
|
event_type.REQUEST.ui_type: SupportedFilter(get=__generic_autocomplete(event_type.REQUEST),
|
|
query=__generic_query(typename=event_type.REQUEST.ui_type),
|
|
change_by_length=True),
|
|
event_type.GRAPHQL.ui_type: SupportedFilter(get=__generic_autocomplete(event_type.GRAPHQL),
|
|
query=__generic_query(typename=event_type.GRAPHQL.ui_type),
|
|
change_by_length=True),
|
|
event_type.STATEACTION.ui_type: SupportedFilter(get=__generic_autocomplete(event_type.STATEACTION),
|
|
query=__generic_query(typename=event_type.STATEACTION.ui_type),
|
|
change_by_length=True),
|
|
event_type.ERROR.ui_type: SupportedFilter(get=__search_pg_errors,
|
|
query=None, change_by_length=True),
|
|
event_type.METADATA.ui_type: SupportedFilter(get=__search_pg_metadata,
|
|
query=None, change_by_length=True),
|
|
# IOS
|
|
event_type.CLICK_IOS.ui_type: SupportedFilter(get=__generic_autocomplete(event_type.CLICK_IOS),
|
|
query=__generic_query(typename=event_type.CLICK_IOS.ui_type),
|
|
change_by_length=True),
|
|
event_type.INPUT_IOS.ui_type: SupportedFilter(get=__generic_autocomplete(event_type.INPUT_IOS),
|
|
query=__generic_query(typename=event_type.INPUT_IOS.ui_type),
|
|
change_by_length=True),
|
|
event_type.VIEW_IOS.ui_type: SupportedFilter(get=__generic_autocomplete(event_type.VIEW_IOS),
|
|
query=__generic_query(typename=event_type.VIEW_IOS.ui_type),
|
|
change_by_length=True),
|
|
event_type.CUSTOM_IOS.ui_type: SupportedFilter(get=__generic_autocomplete(event_type.CUSTOM_IOS),
|
|
query=__generic_query(typename=event_type.CUSTOM_IOS.ui_type),
|
|
change_by_length=True),
|
|
event_type.REQUEST_IOS.ui_type: SupportedFilter(get=__generic_autocomplete(event_type.REQUEST_IOS),
|
|
query=__generic_query(typename=event_type.REQUEST_IOS.ui_type),
|
|
change_by_length=True),
|
|
event_type.ERROR_IOS.ui_type: SupportedFilter(get=__search_pg_errors_ios,
|
|
query=None, change_by_length=True),
|
|
}
|
|
|
|
|
|
def __get_autocomplete_table(value, project_id):
|
|
autocomplete_events = [schemas.FilterType.rev_id,
|
|
schemas.EventType.click,
|
|
schemas.FilterType.user_device,
|
|
schemas.FilterType.user_id,
|
|
schemas.FilterType.user_browser,
|
|
schemas.FilterType.user_os,
|
|
schemas.EventType.custom,
|
|
schemas.FilterType.user_country,
|
|
schemas.EventType.location,
|
|
schemas.EventType.input]
|
|
autocomplete_events.sort()
|
|
sub_queries = []
|
|
for e in autocomplete_events:
|
|
sub_queries.append(f"""(SELECT type, value
|
|
FROM public.autocomplete
|
|
WHERE project_id = %(project_id)s
|
|
AND type= '{e}'
|
|
AND value ILIKE %(svalue)s
|
|
LIMIT 5)""")
|
|
if len(value) > 2:
|
|
sub_queries.append(f"""(SELECT type, value
|
|
FROM public.autocomplete
|
|
WHERE project_id = %(project_id)s
|
|
AND type= '{e}'
|
|
AND value ILIKE %(value)s
|
|
LIMIT 5)""")
|
|
with pg_client.PostgresClient() as cur:
|
|
query = cur.mogrify(" UNION ".join(sub_queries) + ";",
|
|
{"project_id": project_id, "value": helper.string_to_sql_like(value),
|
|
"svalue": helper.string_to_sql_like("^" + value)})
|
|
try:
|
|
cur.execute(query)
|
|
except Exception as err:
|
|
print("--------- AUTOCOMPLETE SEARCH QUERY EXCEPTION -----------")
|
|
print(query.decode('UTF-8'))
|
|
print("--------- VALUE -----------")
|
|
print(value)
|
|
print("--------------------")
|
|
raise err
|
|
results = helper.list_to_camel_case(cur.fetchall())
|
|
return results
|
|
|
|
|
|
def search(text, event_type, project_id, source, key):
|
|
if not event_type:
|
|
return {"data": __get_autocomplete_table(text, project_id)}
|
|
|
|
if event_type in SUPPORTED_TYPES.keys():
|
|
rows = SUPPORTED_TYPES[event_type].get(project_id=project_id, value=text, key=key, source=source)
|
|
# for IOS events autocomplete
|
|
# if event_type + "_IOS" in SUPPORTED_TYPES.keys():
|
|
# rows += SUPPORTED_TYPES[event_type + "_IOS"].get(project_id=project_id, value=text, key=key,
|
|
# source=source)
|
|
elif event_type + "_IOS" in SUPPORTED_TYPES.keys():
|
|
rows = SUPPORTED_TYPES[event_type + "_IOS"].get(project_id=project_id, value=text, key=key,
|
|
source=source)
|
|
elif event_type in sessions_metas.SUPPORTED_TYPES.keys():
|
|
return sessions_metas.search(text, event_type, project_id)
|
|
elif event_type.endswith("_IOS") \
|
|
and event_type[:-len("_IOS")] in sessions_metas.SUPPORTED_TYPES.keys():
|
|
return sessions_metas.search(text, event_type, project_id)
|
|
else:
|
|
return {"errors": ["unsupported event"]}
|
|
|
|
return {"data": rows}
|
|
|
|
|
|
def get_errors_by_session_id(session_id, project_id):
|
|
with pg_client.PostgresClient() as cur:
|
|
cur.execute(cur.mogrify(f"""\
|
|
SELECT er.*,ur.*, er.timestamp - s.start_ts AS time
|
|
FROM {event_type.ERROR.table} AS er INNER JOIN public.errors AS ur USING (error_id) INNER JOIN public.sessions AS s USING (session_id)
|
|
WHERE er.session_id = %(session_id)s AND s.project_id=%(project_id)s
|
|
ORDER BY timestamp;""", {"session_id": session_id, "project_id": project_id}))
|
|
errors = cur.fetchall()
|
|
for e in errors:
|
|
e["stacktrace_parsed_at"] = TimeUTC.datetime_to_timestamp(e["stacktrace_parsed_at"])
|
|
return helper.list_to_camel_case(errors)
|