bg <dZddlZddlZddlZddlZddlZddlZddlZddlZddl m Z ddl Z ddl m Z mZddlmZddlmZddlmZmZmZmZmZmZer ddlmZdd lmZdd lmZdd lmZdd lm Z dd lm!Z!ddlm"Z"ddlm#Z#ddlm$Z$ddlm%Z%ddl&m'Z'ddl(Z ddlm)Z)m*Z*e+Z,e'de+e,e-dZ.e!e-Z/e'de+e"e+e+e-e"e+dZ0e'dde+iZ1e'de!e0e!e/e!e.e e,e1fdZ2e'dde+iZ3e%e+e-e+fZ4e%e4dfZ5e%e-e-fZ6e%e6e5e!e0fZ7e$e%e,e7fZ8 ddl9m:Z;dd lZ>dd!l?m@Z@e=d"d#ZAn#eB$rd$Z;ejCZAd%Z>dZ@YnwxYwd&ZDdaEd'ZFd(ZGd)ZHd*ZId+ZJd,ZKejLZMeMeKfd-ZNd.ZOd/ZPerd0ZQnd1ZQe-d2ZRdtdptdS)N threading_thread)r2r8r9r: is_geventrCs [ ) ) I->y-I-IIr9ec|d}|dS|d}||dkrdS|dd}||dkrdSdS)Nprofiles_samplerTprofiles_sample_rater _experimentsF)get)optionsrGrHs r:has_profiling_enabledrLsp12#t"#9:',@1,D,Dt">2667MNN',@1,D,Dt 5r9cttjddStstjddSt }t r tj}n tj}| d |d}n+| di dp|}|tjks|dkrt|anC|tjkrt|an"td |tjd tj t tjt d S) Nz%[Profiling] Profiler is already setupFz+[Profiling] Profiler requires Python >= 3.3 profiler_moderIr5 frequencyzUnknown profiler mode: {}z.[Profiling] Setting up profiler in {mode} mode)modeT) _schedulerr debugrwarnDEFAULT_SAMPLING_FREQUENCYrCGeventSchedulerrQThreadSchedulerrJ ValueErrorformatsetupatexitregisterteardown_profiler)rKrPdefault_profiler_moderNs r:setup_profilerr_sp <===u  ABBBu*I{{5 !0 4 / 4{{?##/0  KK + + / / @ @ %$  --- G # #$y999 /. . .$y999 4;;MJJKKK L8??Z_?UU O%&&& 4r9cJttdadSr7)rRteardownr8r9r:r]r]s% JJJr9ct|}| |j}|||}| td|D}g}t |D]^\}} || } | -t | |||} || | || _t|t|f} | ||fS)aA Extracts the stack starting the specified frame. The extracted stack assumes the specified frame is the top of the stack, and works back to the bottom of the stack. In the event that the stack is more than `MAX_STACK_DEPTH` frames deep, only the first `MAX_STACK_DEPTH` frames will be returned. maxlenNc34K|]}t|VdSr7)frame_id).0 raw_frames r: z extract_stack..s*FFihy))FFFFFFr9) rf_backappendtuple enumeraterJ extract_framesetlenhash) ricachecwdmax_stack_depth raw_framesrk frame_idsr*ifidframers r: extract_stackr{s o...J  !)$$$    FF:FFFFFI FI&&3 # =!#z!}c::E IIc5 ! ! ! e:Y/H Y &&r9cD|jj|jt|fSr7)f_code co_filenamef_linenoget_frame_name)ris r:rgrg.s   ()*W>W XXr9c|jj} |jd}n#t$rd}YnwxYwtj|||t||pd|d|jdS)N__name__rE)r!r%r"r#r$) r}r~ f_globals Exceptionospathjoinr r)ryrirtr!r%s r:roro3s+H$Z0 GLLh//'99ATF$  s  ++c|jjSr7)r} co_qualname)rzs r:rrRs |''r9c|j}|j}|j} |rU|ddkrId|jvr@|jdjjD](}||jvrd|j|cS)n#t$rYnwxYw |rP|ddkrDd|jvr;|jdjD](}||jvrd|j|cS)n#t$rYnwxYw|S)Nrselfz{}.{}cls) r} co_varnamesco_namef_locals __class____mro____dict__rYrAttributeError)rzr}rr'rs r:rrXsV( ~  B Nf,,en,, >&1;CBBCs|++&~~clDAAAAA,    D   B Ne++U^++ >%08BBCs|++&~~clDAAAAA,    D   s1AA/-A// A<;A<ACC C C gBch| |j}||Sn#t$rYnwxYwtr(t}| |jS#t$rYnwxYw t jj}||Sn#t$rYnwxYw t jj}||Sn#t$rYnwxYwdS)zK Try to get the id of the current thread, with various fall backs. N)identrrCr; thread_identrAcurrent_thread main_thread)threadr gevent_hubcurrent_thread_idmain_thread_ids r:get_current_thread_idrs*  I$  %    D  {{#%%  ! !..!     %466<  ($ $ )       ".006  %! ! &       4sA  A AAA44 BBB"" B/.B/cVeZdZ d dZdZdZdZdZdZdZ d Z d Z d Z d Z dS)ProfileNc|tn||_||_tjj|_|j|_tpd|_ d|_ |j |_ n#t$r d|_ YnwxYwd|_d|_i|_i|_g|_g|_g|_d|_||_dS)NrF)rR schedulerhubuuiduuid4hexevent_idsampledr_default_active_thread_idactive_thread_id_start_timestamp_monotonic_nsstart_nsrstop_nsactiveindexed_framesindexed_stacksr*r+r,unique_samples_profile)r transactionrrs r:__init__zProfile.__init__s(1'8i ( #* *?)@)@)EA& $ 'EDMM   DMMM        # s A++A?>A?ct|_tjd|jdS)Nz.[Profiling] updating active thread id to {tid})tid)rrr rSrYrs r:update_active_thread_idzProfile.update_active_thread_idsM 5 7 7 < C C) D       r9cH|jstjdd|_dS|jtjdd|_dS|jpt jj}|j}| d|_dS|j }t| dr|d|}n,|d |d}n|d d}|tjdd|_dSt|d stj d d|_dStjt|k|_|jrtjd dStjd t|dS)a Sets the profile's sampling decision according to the following precdence rules: 1. If the transaction to be profiled is not sampled, that decision will be used, regardless of anything else. 2. Use `profiles_sample_rate` to decide. z@[Profiling] Discarding profile because transaction is discarded.FNz@[Profiling] Discarding profile because profiler was not started.rGrHrIzA[Profiling] Discarding profile because profiling was not enabled. Profiling)sourcez>[Profiling] Discarding profile because of invalid sample rate.z [Profiling] Initializing profilezk[Profiling] Discarding profile because it's not included in the random sample (sample rate = {sample_rate})) sample_rate)rr rSrr sentry_sdkHubcurrentclientrKcallablerJr warningrandomfloatrY)rsampling_contextrrrKrs r:_set_initial_sampling_decisionz&Profile._set_initial_sampling_decisions|  LR   !DL F > ! LR   !DL Fh0*.0 > DL F. GKK 233 4 4 N5'"456FGGKK + , 8!"89KK!.1556LMMK   LS   !DL F#K DDD  NP   !DL F }{););; <  L; < < < < < L}EE %k 2 2E     r9c|jr|jrdS|js Jdtjdd|_|jst |_|j|dS)NNo scheduler specifiedz[Profiling] Starting profileT)rrrr rSrr start_profilingrs r:startz Profile.start8s{| t{  F~77777~ 3444 } .+--DM &&t,,,,,r9c|jr|jsdS|js Jdtjdd|_|j|t |_dS)Nrz[Profiling] Stopping profileF)rrrr rSstop_profilingr rrs r:stopz Profile.stopDso| 4;  F~77777~ 3444  %%d+++&(( r9c|jptjj}|jd\}}|j}||_|||f|_||S)N)rrrr_stackprofile_context_manager_stater)rr_scope old_profiles r: __enter__zProfile.__enter__OsQh0*.0:b>5m  '*E;&?#  r9cV||j\}}}|`||_dSr7)rrr)rtyvaluetbrrrs r:__exit__zProfile.__exit__]s/ $ ;5+  '# r9cjsdS|jkrdS|jz }|tkrdSxjdz c_t |}|D] \}\}}} |jvrt|D]J\} } | jvrz!Profile.write..s!QQQ8,X6QQQr9r)rrMAX_PROFILE_DURATION_NSrrstrrrnrrqr*rlr+r,rrsysexc_info) rtssampleoffsetrrrrwr*rxrgs ` r:writez Profile.writefs{  F    Fdm# + + + IIKKK F q !$V28 ; ; .C.(Iv ;4#666'0';';:: 8#4+>>>>::::: ;- ; ;s/CD>>*E,+E,chdtjD}|j|j|j|dS)Nc`i|]+}t|jdt|ji,S)r')rrr')rhrs r: z#Profile.process..sH      FK((    r9r))rArnr*r+r,)rr-s r:processzProfile.processsN   $-//    kk|.    r9cx|}t|d|d|d|d|d|jd||dd|d d d t jit jt jd t jt j d |d |ddt|j |j z |dddt|j |jn|j dgd S)Nr*in_app_excludein_app_include project_root environmentpythonreleasestart_timestamp1 architecture)r'versionrr0contextstracetrace_id)idr'relative_start_nsrelative_end_nsrr) rrplatformrr timestamprdevicerruntime transactions)rr rJrrmachinesystemrpython_implementationpython_versionrrrrr)r event_optrKrs r:to_jsonzProfile.to_jsonsZ,,.. H  $ % $ % N #    %==77   }}Y33"#45 0 2 2!))#+-- !688#244 $J/%m4*-(+4<$-+G'H'H )* 5g >z J(+0866!2))'& & & r9cp|jptjj}|j}|dSt |jsdS|j|js%|jr|j dddS|j tkr9|jr|j ddtj ddSdS)NFrr) data_categoryinsufficient_dataz<[Profiling] Discarding profile because insufficient samples.T)rrrrrrLrKr transportrecord_lost_eventrPROFILE_MINIMUM_SAMPLESr rS)rrrs r:validz Profile.validsh0*.0 >5$V^44 5 < t|   22!35  !8 8 8  22'y3 LW X X X5tr9)NN)r __module__ __qualname__rrrrrrrrrrrr8r9r:rrs  '$'$'$'$R   JJJX - - - ) ) )   $$$*;*;*;X   (1 1 1 fr9rcHeZdZdZdZdZdZdZdZdZ dZ d Z d Z d S) Schedulerunknowncd|z |_||_td|_t |_dS)Ng?rbrd)interval make_samplersamplerr new_profilesrpactive_profiles)rrPs r:rzScheduler.__init__sGi ((** "---"uur9c.||Sr7)rZrs r:rzScheduler.__enter__s  r9c.|dSr7)ra)rrrrs r:rzScheduler.__exit__s r9ctr7NotImplementedErrorrs r:rZzScheduler.setup !!r9ctr7rrs r:razScheduler.teardownr r9ctr7rrs r:ensure_runningzScheduler.ensure_runningr r9cb||j|dSr7)r#rrlrrs r:rzScheduler.start_profilings1    )))))r9cdSr7r8r%s r:rzScheduler.stop_profiling r9c`tjtdfd}|S)N)max_sizecx js jsdSt j}t}  fdt jD}n1#t$r$tt j YdSwxYwt|D]3} j j 4g} jD]5}|j r||| ||6|D]} j|dS)z Take a sample of the stack on all the threads in the process. This should be called at a regular interval to collect samples. NcVg|]%\}}t|t|f&Sr8)rr{)rhrrzrsrts r:rzAScheduler.make_sampler.._sample_stack..?sD"UXX}UE3??@r9)rrrqr r_current_framesitemsrrrrangeaddpopleftrrrlremove) r>r?rnowrrinactive_profilesrrsrtrs r: _sample_stackz-Scheduler.make_sampler.._sample_stack&s$ T-A t011L!##C &)&9&;&;&A&A&C&C"   +3<>>:::   <(( F F$(():)B)B)D)DEEEE " / 6 6>6MM#v.... &,,W5555, 5 5$++G4444 5 5s2A((*BB)rgetcwdr)rr5rsrts` @@r:rzScheduler.make_sampler sLikk#&&&= 5= 5= 5= 5= 5= 5= 5~r9N) rrrrQrrrrZrar#rrrr8r9r:rrs D%%% """""""""***    EEEEEr9rcBeZdZdZdZdZfdZdZdZdZ dZ xZ S) rWzr This scheduler is based on running a daemon thread that will call the sampler at a regular interval. rzsentry.profiler.ThreadSchedulerctt||d|_d|_d|_t j|_dS)NrOF) superrWrrunningrpidrALocklockrrPrs r:rzThreadScheduler.__init__qsN ot$$-- -BBB  N$$ r9cdSr7r8rs r:rZzThreadScheduler.setup{r'r9cj|jr)d|_|j|jdSdSdSr=r:rrrs r:razThreadScheduler.teardownE < # DL{&   """"" # #&&r9cntj}|jr |j|krdS|j5|jr|j|kr ddddS||_d|_t j|j|jd|_ |j ddddS#1swxYwYdS)NT)r'targetdaemon) rgetpidr:r;r=rAThreadr'runrrrr;s r:r#zThreadScheduler.ensure_runningsikk < DHOO F Y  | C         DHDL $* $(SWXXXDK K                       sB*A B**B.1B.c tj}|jrh|tj|z }||jkrt |j|z tj}|jfdSdSr7r4 perf_counterr:rr thread_sleeprlastelapseds r:rHzThreadScheduler.run ""l ' LLNNN '))D0G&&T]W4555$&&Dl ' ' ' ' 'r9 rrr__doc__rQr'rrZrar#rH __classcell__rs@r:rWrWhs D ,D%%%%%   ###   0'''''''r9rWcBeZdZdZdZdZfdZdZdZdZ dZ xZ S) rVas This scheduler is based on the thread scheduler but adapted to work with gevent. When using gevent, it may monkey patch the threading modules (`threading` and `_thread`). This results in the use of greenlets instead of native threads. This is an issue because the sampler CANNOT run in a greenlet because 1. Other greenlets doing sync work will prevent the sampler from running 2. The greenlet runs in the same thread as other greenlets so when taking a sample, other greenlets will have been evicted from the thread. This results in a sample containing only the sampler's code. geventzsentry.profiler.GeventSchedulerct'td|jt t ||d|_d|_d|_ tj |_ dS)Nz"Profiler mode: {} is not availablerOF) r3rXrYrQr9rVrr:rr;rAr<r=r>s r:rzGeventScheduler.__init__sw  AHHSSTT T ot$$-- -BBB   N$$ r9cdSr7r8rs r:rZzGeventScheduler.setupr'r9cj|jr)d|_|j|jdSdSdSr=rArs r:razGeventScheduler.teardownrBr9cVtj}|jr |j|krdS|j5|jr|j|kr ddddS||_d|_t d|_|j|jddddS#1swxYwYdS)NTr) rrFr:r;r=r3rspawnrHrIs r:r#zGeventScheduler.ensure_runnings ikk < DHOO F Y ( (| C ( ( ( ( ( ( ( (DHDL$Q--DK K  dh ' ' ' ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (sBABB"%B"c tj}|jrh|tj|z }||jkrt |j|z tj}|jfdSdSr7rKrNs r:rHzGeventScheduler.runrQr9rRrUs@r:rVrVs   D ,D%%%%%$   ###(((*'''''''r9rVr7)YrSr[rrrrrAr4r collectionsrrsentry_sdk._compatrrsentry_sdk._lru_cachersentry_sdk._typesrsentry_sdk.utilsrr r r r r typesrtypingrrrrrrrrrtyping_extensionsrsentry_sdk.tracingrrrThreadIdintrProcessedStackr r&r(r.FrameIdFrameIdsStackIdExtractedStackExtractedSamplerWr0r; gevent.monkeyr1r2gevent.threadpoolr3rM ImportErrorr5rCrRrUrrLr_r]MAX_STACK_DEPTHr6CWDr{rgrorrrobjectrrrWrVr8r9r:rus6   **************++++++J@++++++????????Hi&)!  O#YNY  sm     N(i!   !y>*>*O,#H.E$EF   Y sN     G Wc\"H CHoG7Hd>.BBCNuX~%=>?O000000========,,,,,,<00LL   :L JJJ  JJJ  ! "111hbikk # -'-'-'-'`YYY : 5(((( ---`#d))++++\yyyyyfyyyx ppppppppfF'F'F'F'F'iF'F'F'RS'S'S'S'S'iS'S'S'S'S's" FFF