
    jKjE                         d Z ddlZddlZddlZddlZddlmZmZmZ ddl	m
Z
 ddlmZ dZdZd	Z ej                   d
      Z G d d      ZdgZy)aL  
Integration for `celery`_ to capture task lifecycle events and exceptions with PostHog.

.. _celery: https://pypi.org/project/celery/

Features:
- Hooks into Celery signals to automatically capture task lifecycle events
  (started, success, failure, retry, published) and exceptions.
- Lifecycle events include Celery-specific properties such as task ID, task name,
  queue, retry count, duration, Celery version etc.
- Any custom events captured inside a task (via ``client.capture``) are automatically
  enriched with the same Celery-specific properties via context tags.
- Propagates PostHog context (distinct ID, session ID, tags) from the producer
  process to the worker process.

Supports Celery 4.0+ (Message Protocol Version 2).

Usage
-----

.. code-block:: python

    from posthog import Posthog
    from posthog.integrations.celery import PosthogCeleryIntegration

    # ... init Posthog client

    integration = PosthogCeleryIntegration()
    integration.instrument()

    # ... publish tasks or run workers ...

    integration.shutdown()
    posthog.shutdown()

See ``examples/celery_integration.py`` for a complete working example.

Supported task states for event emission:
    - ``published``
    - ``started``
    - ``success``
    - ``failure``
    - ``retry``

Event properties:
    All lifecycle and exception events include the following properties:

    - ``celery_task_id`` -- unique task ID
    - ``celery_task_name`` -- registered task name
    - ``celery_state`` -- lifecycle state (started, success, failure, etc.)
    - ``celery_hostname`` -- worker hostname
    - ``celery_exchange`` -- broker exchange
    - ``celery_routing_key`` -- broker routing key
    - ``celery_queue`` -- broker queue name
    - ``celery_retry_count`` -- number of retries so far
    - ``celery_version`` -- installed Celery library version
    - ``celery_task_duration_ms`` -- task wall-clock duration in milliseconds
      (present on terminal states: success, failure, retry)

    Additional properties on specific states:

    - **failure**: ``error_type``, ``error_message``
    - **retry**: ``celery_reason``
    N)AnyCallableOptional   )contexts)ClientzX-POSTHOG-DISTINCT-IDzX-POSTHOG-SESSION-IDzX-POSTHOG-CONTEXT-TAGSposthogc                      e Zd ZdZ	 	 	 	 	 d&dee   dedededeeee   e	ee
f   gef      f
dZd'd
Zd'dZd'dZd'dZd'dZd Zd Zd Zd Zd Zd Z	 d(dedee	ee
f      d	dfdZde
d	dfdZde
d	e	ee
f   fdZde
d	e	ee
f   fdZ	 	 	 d)d	e	ee
f   fdZde
de	ee
f   d	dfdZdee   de	ee
f   d	efd Zd!ed"e	ee
f   d	dfd#Zd$ed	dfd%Z y)*PosthogCeleryIntegrationaw  Celery integration that captures task lifecycle events and exceptions.

    Args:
        client: Optional ``Client`` instance. When provided, all events and
            exceptions are captured through this client rather than the
            global ``posthog`` module. Don't skip this if using a custom flag
            definition cache provider, and pass the custom ``Client`` instance
            here initialized with the custom provider so fork safety for that
            provider is handled correctly.
        capture_exceptions: Whether to capture task exceptions via
            ``capture_exception`` (default ``True``).
        capture_task_lifecycle_events: Whether to emit lifecycle events of the task
            such as "started", "success", "failure" etc. (default ``True``).
        propagate_context: Whether to propagate PostHog context (distinct
            ID, session ID, tags) from the producer to the worker via task
            headers (default ``True``).
        task_filter: Optional callback ``(task_name, task_properties) -> bool`` expected to
            return ``False`` if a given task should not be tracked.
    Nclientcapture_exceptionscapture_task_lifecycle_eventspropagate_contexttask_filterc                     || _         || _        || _        || _        || _        d| _        d| _        d | _        d | _        y NF)	r   r   r   r   r   _instrumented
_shut_down_signals_celery_version)selfr   r   r   r   r   s         l/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/posthog/integrations/celery.py__init__z!PosthogCeleryIntegration.__init__h   sI     "4-J*!2&"'+.2    returnc                    | j                   ryddlm} ddlm} d| _        || _        || _        |j                  j                  | j                  d       |j                  j                  | j                  d       |j                  j                  | j                  d       |j                  j                  | j                  d       |j                   j                  | j"                  d       |j$                  j                  | j&                  d       |j(                  j                  | j*                  d       t-        j.                  | j0                         d| _         y)a3  Connect Celery signal handlers to capture task events and exceptions.
        Call this after initializing the PostHog client and this integration.

        If Celery runs on a single host, reinstrumenting in worker children is
        not strictly necessary because the PostHog client and this integration
        are fork-safe. If Celery workers run across multiple hosts, each worker
        process must initialize PostHog, this integration, and call
        ``instrument()``. Celery provides ``worker_process_init`` signal to help
        with this.
        Nr   )signals)__version__F)weakT)r   celeryr   r   r   r   r   task_prerunconnect_on_task_preruntask_success_on_task_successtask_failure_on_task_failure
task_retry_on_task_retrybefore_task_publish_on_before_task_publishafter_task_publish_on_after_task_publishworker_process_shutdown_on_worker_process_shutdownatexitregistershutdown)r   r   celery_versions      r   
instrumentz#PosthogCeleryIntegration.instrument{   s$    "8-##D$8$8u#E$$T%:%:$G$$T%:%:$G""4#6#6U"C##++D,H,Hu+U""**4+F+FU*S''//,,5 	0 	
 	&!r   c                    | j                   r| j                  sy | j                  j                  j                  | j                         | j                  j
                  j                  | j                         | j                  j                  j                  | j                         | j                  j                  j                  | j                         | j                  j                  j                  | j                         | j                  j                  j                  | j                         | j                  j                  j                  | j                          d | _        d| _         y r   )r   r   r!   
disconnectr#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r   s    r   _disconnect_signalsz,PosthogCeleryIntegration._disconnect_signals   s    !!!!,,T-A-AB""--d.C.CD""--d.C.CD  ++D,?,?@))44T5Q5QR((33D4O4OP--88,,	
 "r   c                 b    | j                          t        j                  | j                         y)zDisconnect Celery signal handlers and unregister exit cleanup.

        Do not use directly, call `shutdown()` instead.
        N)r8   r0   
unregisterr2   r7   s    r   uninstrumentz%PosthogCeleryIntegration.uninstrument   s"    
 	  "$--(r   c                    | j                   ry	 | j                          | j                  r| j                  j                          nddlm}  |        | j                          d| _         y# t        $ r t        j                  d       Y yw xY w)a  Disconnect all signal handlers registered by ``instrument()``, flush all pending events
        and cleanly shutdown the integration.

        ``shutdown()`` is also registered on ``worker_process_shutdown`` and ``atexit`` signals,
        but there is no guarantee those will always be called, so we strongly recommend calling
        it manually when the integration is no longer needed to avoid data loss.
        Nr   )flushTz.Failed to shut down PostHog Celery integration)	r   r8   r   r=    r;   	Exceptionlogger	exception)r   r=   s     r   r2   z!PosthogCeleryIntegration.shutdown   sr     ??	O$$&{{!!#$"DO 	OMN	Os   AA+ +BBc                 $    | j                          y N)r2   r   argskwargss      r   r/   z4PosthogCeleryIntegration._on_worker_process_shutdown   s    r   c                    	 | j                   sy |j                  d      }t        |t              sy t	        j
                         }t	        j                         }t	        j                         }i }|r	||t        <   |r	||t        <   |r"t        j                  |t              |t        <   |r3|j                  |       |j                  di       j                  |       y y # t         $ r t"        j%                  d       Y y w xY w)Nheaders)defaultz:Failed to propagate PostHog context in before_task_publish)r   get
isinstancedictr   get_context_distinct_idget_context_session_idget_tagsCONTEXT_DISTINCT_ID_HEADERCONTEXT_SESSION_ID_HEADERjsondumpsstrCONTEXT_TAGS_HEADERupdate
setdefaultr?   r@   rA   )r   rE   rF   rH   distinct_id
session_idtagsposthog_headerss           r   r+   z0PosthogCeleryIntegration._on_before_task_publish   s    	))jj+Ggt,"::<K!88:J$$&D.0O>I :;=G 9:7;zz$PS7T 34/ ""9b188I   	L	s   C !C B,C D ?D c           
         	 | j                   sy |j                  d      }|j                  d      }t        |t              r|j                  d      nd }||d|j                  d      |j                  d      d t        |t              r|j                  d      nd | j                  d}| j                  ||      r| j                  d	|
       y y # t        $ r t        j                  d       Y y w xY w)NsenderrH   id	publishedexchangerouting_keyretries)celery_task_idcelery_task_namecelery_statecelery_exchangecelery_routing_keycelery_hostnamecelery_retry_countr3   zcelery task published
propertiesz;Failed to capture Celery after_task_publish lifecycle event)
r   rJ   rK   rL   r   _should_track_capture_eventr?   r@   rA   )r   rE   rF   r]   rH   task_idsender_propertiess          r   r-   z/PosthogCeleryIntegration._on_after_task_publish   s    	55ZZF jj+G+5gt+Dgkk$'$G #*$* +#)::j#9&,jj&?#'gt, '.kk)&<"&"6"6! !!&*;<##+8I $  =  	M	s   C B>C C0/C0c                 
   d }	 |j                  d      }|sy |j                  d      }t        |dd       }| j                  |      }| j                  ||d      }|j                  d      }	|Rt	        j
                  dd| j                  	      }|j                          ||_        t        j                         |_        | j                  |       i ||}
|
j                         D ]  \  }}t	        j                  ||        | j                  r'| j!                  |	|      r| j#                  d
|       y y y # t$        $ r@ t&        j)                  d       |&	 |j+                  d d d        Y y # t$        $ r Y Y y w xY wY y w xY w)Nrn   r]   requeststartedr]   rn   staterd   TF)freshr   r   zcelery task startedrj   z$Failed to process Celery task_prerun)rJ   getattr_extract_propagated_tags_build_task_propertiesr   new_contextr   	__enter___posthog_ctxtime	monotonic_posthog_start_apply_propagated_identityitemstagr   rl   rm   r?   r@   rA   __exit__)r   rE   rF   context_managerrn   r]   rq   context_tagstask_properties	task_namemerged_tagskeyvalues                r   r#   z(PosthogCeleryIntegration._on_task_prerun  s   )	jj+GZZ)Ffi6G88AL"99 : O
 (++,>?I""*"6"6',;;#
  ))+'6$)-)9&++G4=_==K)//1
US%( 2 11d6H6H?7 ##$9o#V71  	CD*#,,T4>   +	s5   D9 DD9 9 FE//	E<8F;E<<FFc                 (     | j                   di | y )N)success_handle_task_endrD   s      r   r%   z)PosthogCeleryIntegration._on_task_successE      262r   c                 (     | j                   di | y )N)failurer   rD   s      r   r'   z)PosthogCeleryIntegration._on_task_failureH  r   r   c           
      b     | j                   	 dddt        |j                  d            ii| y )Nextra_propertiescelery_reasonreason)retry)r   rT   rJ   rD   s      r   r)   z'PosthogCeleryIntegration._on_task_retryK  s>    	
  VZZ%9!:	

 	
r   rt   r   c                 
   |j                  d      }t        |dd       }	 |j                  d      }|t        |dd       }| j                  |||      }|r|j                  |       | j	                  ||       |j                  d      }|rCt        |      j                  |d<   t        |      |d<   | j                  r| j                  |       |j                  d	      }	| j                  r(| j                  |	|      r| j                  d
| |       t        |dd       }
|
|
j!                  d d d        y y # t        $ r t        j                  d|       Y Ew xY w# t        |dd       }
|
|
j!                  d d d        w w xY w)Nr]   rq   rn   r^   rs   rA   
error_typeerror_messagerd   zcelery task rj   z!Failed to process Celery %s stater{   )rJ   rv   rx   rV   _add_durationtype__name__rT   r   _capture_exceptionr   rl   rm   r?   r@   rA   r   )r   rt   r   rF   r]   rq   rn   r   rA   r   ctxs              r   r   z)PosthogCeleryIntegration._handle_task_endT  s    H%&)T2 	/jj+G!'46"99 : O
  &&'78w8

;/I04Y0H0H-36y>0**++I6'++,>?I11d6H6H?7 ##l5'$:#W '>48CT4. 	  	I@%H	I '>48CT4. s$   C4D8 8EE EE %Frq   c                     | j                  |      }|j                  t              }|rt        j                  t        |             |j                  t              }|rt        j                  t        |             y y rC   )_extract_headersrJ   rP   r   identify_contextrT   rQ   set_context_session)r   rq   rH   rX   rY   s        r   r   z3PosthogCeleryIntegration._apply_propagated_identity  s`    ''0kk"<=%%c+&67[[!:;
((Z9 r   c                     | j                  |      }|j                  t              }t        |t        t
        t        f      si S 	 t        j                  |      }t        |t              r|S i S # t        $ r i cY S w xY wrC   )r   rJ   rU   rK   rT   bytes	bytearrayrR   loadsr?   rL   )r   rq   rH   raw_tagsparseds        r   rw   z1PosthogCeleryIntegration._extract_propagated_tags  sv    ''0;;23(S%$;<I	ZZ)F fd#M	  	I	s   A. .A<;A<c                     |i S t        |dd       }t        |t              r|S t        |t              r#|j                  d      }t        |t              r|S i S )NrH   )rv   rK   rL   rJ   )r   rq   rH   dict_headerss       r   r   z)PosthogCeleryIntegration._extract_headers  sX    ?I
 '9d3gt$Ngt$";;y1L,-##	r   c                 *   t        |dd       }t        |dd       }t        |t              r|ni }|t        |dd       |t        |dd       |j                  d      |j                  d      |j                  d      t        |dd       | j                  d		}|S )
Nrq   delivery_infonamehostnamer`   ra   queuerb   )	rc   rd   re   rh   rf   rg   celery_queueri   r3   )rv   rK   rL   rJ   r   )r   r]   rn   rt   rq   r   rk   s          r   rx   z/PosthogCeleryIntegration._build_task_properties  s     &)T2$?)3M4)Hb & ' =!&w
DA,00<"/"3"3M"B)--g6")'9d"C"22


 r   r   c                 r    t        |dd       }|(t        t        j                         |z
  dz  d      |d<   y y )Nr~   g     @@   celery_task_duration_ms)rv   roundr|   r}   )r   rq   r   
start_times       r   r   z&PosthogCeleryIntegration._add_duration  sB    W&6=
!9>!J.&8!:O56 "r   r   c                 R    | j                   rt        | j                  ||            S y)NT)r   bool)r   r   r   s      r   rl   z&PosthogCeleryIntegration._should_track  s(     ((ODEEr   eventrk   c                 x    | j                   r| j                   j                  ||       y ddlm}  |||       y )Nrj   r   )capture)r   r   r	   )r   r   rk   r   s       r   rm   z'PosthogCeleryIntegration._capture_event  s-    ;;KK*='Ej1r   rA   c                 p    | j                   r| j                   j                  |       y ddlm}  ||       y )Nr   )capture_exception)r   r   r	   )r   rA   r   s      r   r   z+PosthogCeleryIntegration._capture_exception  s&    ;;KK)))41i(r   )NTTTN)r   NrC   )NNN)!r   
__module____qualname____doc__r   r   r   r   rT   rL   r   r   r4   r8   r;   r2   r/   r+   r-   r#   r%   r'   r)   r   r   rw   r   rx   r   rl   rm   r?   r    r   r   r   r   S   s   , $(#'.2"&QU3 3 !3 (,	3
  3 htCH~'F'LMN3&!"F#$)O4 DB+Z33
 6:)/)/ #4S>2)/
 
)/V:# :$ : S#X   S#X ( 	
 
c3h.S 4S> d !#9=c3h	2C 2T#s(^ 2 2)I )$ )r   r   )r   r0   rR   loggingr|   typingr   r   r   r>   r   r   r   rP   rQ   rU   	getLoggerr@   r   __all__r   r   r   <module>r      sd   ?B     * *   5 2 . 			9	%K) K)^ r   