Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction to Gokit

myoung-su,shin
August 15, 2015
140

Introduction to Gokit

myoung-su,shin

August 15, 2015
Tweet

Transcript

  1. RPC Server 작성하기 t y p e A d d

    R e q u e s t s t r u c t { A , B i n t 6 4 } t y p e A d d R e s p o n s e s t r u c t { V i n t 6 4 } t y p e H a n d l e r s t r u c t { } f u n c ( h H a n d l e r ) A d d ( r e q A d d R e q u e s t , r e s * A d d R e s p o n s e ) e r r o r { r e s . V = r e q . A + r e q . B r e t u r n n i l } f u n c m a i n ( ) { v a r a d d = n e w ( H a n d l e r ) s : = r p c . N e w S e r v e r ( ) s . R e g i s t e r N a m e ( " a d d s v c " , a d d ) s . H a n d l e H T T P ( r p c . D e f a u l t R P C P a t h , r p c . D e f a u l t D e b u g P a t h ) g o h t t p . L i s t e n A n d S e r v e ( a d d r , s ) t i m e . S l e e p ( 1 * t i m e . S e c o n d ) r e t : = C l i e n t C a l l ( 1 , 2 ) l o g . P r i n t l n ( " r e t : " , r e t ) } Run
  2. 입력받은 a,b를 더하는 비지니스 로직에 대한 RPC(net/rpc) 서버를 만들었다. 여기서,

    실제로 서비스를 하기 위해서 무엇을 더해야 할까? https://blog.twitter.com/2011/finagle-a-protocol-agnostic-rpc-system
  3. (공통적인?!) 필요한 기능 여러 서버가 각기 다른 Transport(HTTP/JSON,gRPC,Thirft,Protobuf)을 사용하더라도, 비슷

    한 기능이 필요하다 운영중인 서버의 상태를 모니터링하고 싶다. - p a c k a g e l o g - p a c k a g e m e t r i c - p a c k a g e t r a c i n g 다른 서버/서비스에 접속하기 위해,접속 가능한 접속 정보를 알거나 알려주어야 한다. - s e r v i c e d i s c o v e r y - p a c k a g e l o a d b a l a n c e r 네트웍 요청에 대한 제한을 주는 등으로 가능한 안정성을 부여하고 싶다. - p a c k a g e r a t e l i m i t - p a c k a g e c i r c u i t b r e a k e r 기타 등등
  4. package endpoint / / E n d p o i

    n t i s t h e f u n d a m e n t a l b u i l d i n g b l o c k o f s e r v e r s a n d c l i e n t s . / / I t r e p r e s e n t s a s i n g l e R P C m e t h o d . t y p e E n d p o i n t f u n c ( c t x c o n t e x t . C o n t e x t , r e q u e s t i n t e r f a c e { } ) ( r e s p o n s e i n t e r f a c e { } , e r r e r r o r ) / / M i d d l e w a r e i s a c h a i n a b l e b e h a v i o r m o d i f i e r f o r e n d p o i n t s . t y p e M i d d l e w a r e f u n c ( E n d p o i n t ) E n d p o i n t Endpoint은 하나의 RPC 메소드를 나타낸다 Gokit의 가장 기본적인 인터페이스 Middleware : Endpoint을 받아서 Endpoint을 반환하는 함수로 Endpoint의 기능을 확장 한다. - r a t e l i m i t - t r a c i n g - c i r c u i t b r e a k e r - l o a d b a l a n c e r - . . .
  5. StringService t y p e S t r i n

    g S e r v i c e i n t e r f a c e { U p p e r c a s e ( s t r i n g ) ( s t r i n g , e r r o r ) C o u n t ( s t r i n g ) i n t } t y p e s t r i n g S e r v i c e s t r u c t { } f u n c ( s t r i n g S e r v i c e ) U p p e r c a s e ( s s t r i n g ) ( s t r i n g , e r r o r ) { i f s = = " " { r e t u r n " " , E r r E m p t y } r e t u r n s t r i n g s . T o U p p e r ( s ) , n i l } f u n c ( s t r i n g S e r v i c e ) C o u n t ( s s t r i n g ) i n t { r e t u r n l e n ( s ) } S t r i n g S e r v i c e 인터페이스로 비지니스 모델을 정의한다.
  6. Request와 Response t y p e U p p e

    r c a s e R e q u e s t s t r u c t { S s t r i n g ` j s o n : " s " ` } t y p e U p p e r c a s e R e s p o n s e s t r u c t { V s t r i n g ` j s o n : " v " ` E r r e r r o r ` j s o n : " e r r " ` } t y p e C o u n t R e q u e s t s t r u c t { S s t r i n g ` j s o n : " s " ` } t y p e C o u n t R e s p o n s e s t r u c t { V i n t ` j s o n : " v " ` } S t r i n g S e r v i c e 의 R P C 메소드의 요청( R e q u e s t )와 응답( R e s p o n s e )을 s t r u c t 으로 구성
  7. Endpoint t y p e E n d p o

    i n t f u n c ( c t x c o n t e x t . C o n t e x t , r e q u e s t i n t e r f a c e { } ) ( r e s p o n s e i n t e r f a c e { } , e r r e r r o r ) f u n c m a k e U p p e r c a s e E n d p o i n t ( s v c S t r i n g S e r v i c e ) e n d p o i n t . E n d p o i n t { r e t u r n f u n c ( c t x c o n t e x t . C o n t e x t , r e q u e s t i n t e r f a c e { } ) ( i n t e r f a c e { } , e r r o r ) { r e q : = r e q u e s t . ( U p p e r c a s e R e q u e s t ) v , e r r : = s v c . U p p e r c a s e ( r e q . S ) r e t u r n U p p e r c a s e R e s p o n s e { v , e r r } , n i l } } f u n c m a k e C o u n t E n d p o i n t ( s v c S t r i n g S e r v i c e ) e n d p o i n t . E n d p o i n t { r e t u r n f u n c ( c t x c o n t e x t . C o n t e x t , r e q u e s t i n t e r f a c e { } ) ( i n t e r f a c e { } , e r r o r ) { r e q : = r e q u e s t . ( C o u n t R e q u e s t ) v : = s v c . C o u n t ( r e q . S ) r e t u r n C o u n t R e s p o n s e { v } , n i l } }
  8. Transport / / N e t R p c '

    s h a n d l e r t y p e N e t R p c B i n d i n g s t r u c t { C o n t e x t c o n t e x t . C o n t e x t u p p e r c a s e E n d p o i n t e n d p o i n t . E n d p o i n t c o u n t E n d p o i n t e n d p o i n t . E n d p o i n t } E n d p o i n t 을 R P C 라이브러리(net/rpc,grpc,thrift,...)에 필요한 형태로 사용할수 있도록 H T T P 의 경우, g i t h u b . c o m / g o - k i t / k i t / t r a n s p o r t / h t t p 에 helper struct가 있다 u p p e r c a s e H a n d l e r : = h t t p t r a n s p o r t . S e r v e r { C o n t e x t : c t x , E n d p o i n t : m a k e U p p e r c a s e E n d p o i n t ( s v c ) , D e c o d e F u n c : d e c o d e U p p e r c a s e R e q u e s t , E n c o d e F u n c : e n c o d e R e s p o n s e , } c o u n t H a n d l e r : = h t t p t r a n s p o r t . S e r v e r { C o n t e x t : c t x , E n d p o i n t : m a k e C o u n t E n d p o i n t ( s v c ) , D e c o d e F u n c : d e c o d e C o u n t R e q u e s t , E n c o d e F u n c : e n c o d e R e s p o n s e , }
  9. context.Context http://blog.golang.org/context t y p e C o n t

    e x t i n t e r f a c e { D o n e ( ) < - c h a n s t r u c t { } / / c l o s e d w h e n t h i s C o n t e x t i s c a n c e l e d E r r ( ) e r r o r / / w h y t h i s C o n t e x t w a s c a n c e l e d D e a d l i n e ( ) ( d e a d l i n e t i m e . T i m e , o k b o o l ) / / w h e n t h i s C o n t e x t w i l l b e c a n c e l e d V a l u e ( k e y i n t e r f a c e { } ) i n t e r f a c e { } / / d a t a a s s o c i a t e d w i t h t h i s C o n t e x t } Context들은 계층구조를 가진다 (상위 Context의 value가 파생된 Context에게 전달된다) t y p e C a n c e l F u n c t y p e C o n t e x t f u n c B a c k g r o u n d ( ) C o n t e x t f u n c T O D O ( ) C o n t e x t f u n c W i t h C a n c e l ( p a r e n t C o n t e x t ) ( c t x C o n t e x t , c a n c e l C a n c e l F u n c ) f u n c W i t h D e a d l i n e ( p a r e n t C o n t e x t , d e a d l i n e t i m e . T i m e ) ( C o n t e x t , C a n c e l F u n c ) f u n c W i t h T i m e o u t ( p a r e n t C o n t e x t , t i m e o u t t i m e . D u r a t i o n ) ( C o n t e x t , C a n c e l F u n c ) f u n c W i t h V a l u e ( p a r e n t C o n t e x t , k e y i n t e r f a c e { } , v a l i n t e r f a c e { } ) C o n t e x t
  10. f u n c ( n N e t R

    p c B i n d i n g ) U p p e r c a s e ( r e q U p p e r c a s e R e q u e s t , r e s * U p p e r c a s e R e s p o n s e ) e r r o r { c t x , c a n c e l : = c o n t e x t . W i t h C a n c e l ( n . C o n t e x t ) d e f e r c a n c e l ( ) r e s p o n s e s : = m a k e ( c h a n U p p e r c a s e R e s p o n s e , 1 ) e r r s : = m a k e ( c h a n e r r o r , 1 ) g o f u n c ( ) { r e s p , e r r : = n . u p p e r c a s e E n d p o i n t ( c t x , r e q ) i f e r r ! = n i l { e r r s < - e r r r e t u r n } r e s p o n s e s < - r e s p . ( U p p e r c a s e R e s p o n s e ) } ( ) s e l e c t { c a s e < - c t x . D o n e ( ) : r e t u r n c o n t e x t . D e a d l i n e E x c e e d e d c a s e e r r : = < - e r r s : r e t u r n e r r c a s e r e s p : = < - r e s p o n s e s : ( * r e s ) = r e s p r e t u r n n i l } }
  11. f u n c ( n N e t R

    p c B i n d i n g ) C o u n t ( r e q C o u n t R e q u e s t , r e s * C o u n t R e s p o n s e ) e r r o r { c t x , c a n c e l : = c o n t e x t . W i t h C a n c e l ( n . C o n t e x t ) d e f e r c a n c e l ( ) r e s p o n s e s : = m a k e ( c h a n C o u n t R e s p o n s e , 1 ) e r r s : = m a k e ( c h a n e r r o r , 1 ) g o f u n c ( ) { r e s p , e r r : = n . c o u n t E n d p o i n t ( c t x , r e q ) i f e r r ! = n i l { e r r s < - e r r r e t u r n } r e s p o n s e s < - r e s p . ( C o u n t R e s p o n s e ) } ( ) s e l e c t { c a s e < - c t x . D o n e ( ) : r e t u r n c o n t e x t . D e a d l i n e E x c e e d e d c a s e e r r : = < - e r r s : r e t u r n e r r c a s e r e s p : = < - r e s p o n s e s : ( * r e s ) = r e s p r e t u r n n i l } }
  12. Main f u n c m a i n (

    ) { c t x : = c o n t e x t . B a c k g r o u n d ( ) s v c : = s t r i n g S e r v i c e { } n e t R p c B i n d i n g : = N e t R p c B i n d i n g { c t x , m a k e U p p e r c a s e E n d p o i n t ( s v c ) , m a k e C o u n t E n d p o i n t ( s v c ) } s : = r p c . N e w S e r v e r ( ) s . R e g i s t e r N a m e ( " s t r i n g s v c " , n e t R p c B i n d i n g ) s . H a n d l e H T T P ( r p c . D e f a u l t R P C P a t h , r p c . D e f a u l t D e b u g P a t h ) g o f u n c ( ) { e r r : = h t t p . L i s t e n A n d S e r v e ( " : 8 0 8 0 " , s ) i f e r r ! = n i l { l o g . F a t a l ( e r r ) } } ( ) t i m e . S l e e p ( 1 * t i m e . S e c o n d ) c l i e n t , _ : = r p c . D i a l H T T P ( " t c p " , " l o c a l h o s t : 8 0 8 0 " ) / / s o r r y f o r i g n o r e t h e e r r o r c l i e n t E n d p o i n t : = N e w N e t R p c C l i e n t ( c l i e n t ) r e q : = U p p e r c a s e R e q u e s t { S : " g o k i t ! " } r e s , e r r : = c l i e n t E n d p o i n t ( c t x , r e q ) l o g . P r i n t l n ( " r e s : " , r e s . ( U p p e r c a s e R e s p o n s e ) . V , " e r r : " , e r r ) } Run
  13. Client f u n c N e w N e

    t R p c C l i e n t ( c * r p c . C l i e n t ) e n d p o i n t . E n d p o i n t { r e t u r n f u n c ( c t x c o n t e x t . C o n t e x t , r e q u e s t i n t e r f a c e { } ) ( i n t e r f a c e { } , e r r o r ) { e r r s : = m a k e ( c h a n e r r o r , 1 ) r e s p o n s e s : = m a k e ( c h a n i n t e r f a c e { } , 1 ) g o f u n c ( ) { v a r r e s p o n s e U p p e r c a s e R e s p o n s e i f e r r : = c . C a l l ( " s t r i n g s v c . U p p e r c a s e " , r e q u e s t , & r e s p o n s e ) ; e r r ! = n i l { e r r s < - e r r r e t u r n } r e s p o n s e s < - r e s p o n s e } ( ) s e l e c t { c a s e < - c t x . D o n e ( ) : r e t u r n n i l , c o n t e x t . D e a d l i n e E x c e e d e d c a s e e r r : = < - e r r s : r e t u r n n i l , e r r c a s e r e s p : = < - r e s p o n s e s : r e t u r n r e s p , n i l } } } Client도 역시...
  14. Example: LRU Cache Endpoint t y p e C a

    c h e K e y F u n c f u n c ( r e q u e s t i n t e r f a c e { } ) ( i n t e r f a c e { } , b o o l ) f u n c N e w L R U C a c h e ( c a c h e * l r u . C a c h e , c a c h e K e y C a c h e K e y F u n c ) e n d p o i n t . M i d d l e w a r e { r e t u r n f u n c ( n e x t e n d p o i n t . E n d p o i n t ) e n d p o i n t . E n d p o i n t { r e t u r n f u n c ( c t x c o n t e x t . C o n t e x t , r e q u e s t i n t e r f a c e { } ) ( i n t e r f a c e { } , e r r o r ) { k e y , o k : = c a c h e K e y ( r e q u e s t ) i f ! o k { r e t u r n n e x t ( c t x , r e q u e s t ) } v a l , o k : = c a c h e . G e t ( k e y ) i f o k { f m t . P r i n t l n ( " R e t u r n f r o m c a c h e " , r e q u e s t , v a l ) r e t u r n v a l , n i l } v a l , e r r : = n e x t ( c t x , r e q u e s t ) i f e r r = = n i l { c a c h e . A d d ( k e y , v a l ) } f m t . P r i n t l n ( " R e t u r n f r o m e n d p o i n t " , r e q u e s t , v a l ) r e t u r n v a l , e r r } } } Run
  15. c a c h e K e y F u

    n c : = f u n c ( r e q u e s t i n t e r f a c e { } ) ( i n t e r f a c e { } , b o o l ) { i f r e q , o k : = r e q u e s t . ( U p p e r c a s e R e q u e s t ) ; o k { r e t u r n r e q . S , t r u e } r e t u r n n i l , f a l s e } c a c h e , _ : = l r u . N e w ( 1 0 ) e : = m a k e U p p e r c a s e E n d p o i n t ( s v c ) e = N e w L R U C a c h e ( c a c h e , c a c h e K e y F u n c ) ( e ) r e q : = U p p e r c a s e R e q u e s t { " g o p h e r c o n ! " } r e s p , e r r : = e ( c o n t e x t . B a c k g r o u n d ( ) , r e q ) f m t . P r i n t l n ( " r e s p " , r e s p . ( U p p e r c a s e R e s p o n s e ) . V , " e r r " , e r r ) r e s p , e r r = e ( c o n t e x t . B a c k g r o u n d ( ) , r e q ) f m t . P r i n t l n ( " r e s p " , r e s p . ( U p p e r c a s e R e s p o n s e ) . V , " e r r " , e r r )
  16. package logging f u n c l o g g

    i n g ( l o g g e r l o g . L o g g e r ) e n d p o i n t . M i d d l e w a r e { r e t u r n f u n c ( n e x t e n d p o i n t . E n d p o i n t ) e n d p o i n t . E n d p o i n t { r e t u r n f u n c ( c t x c o n t e x t . C o n t e x t , r e q u e s t i n t e r f a c e { } ) ( i n t e r f a c e { } , e r r o r ) { l o g g e r . L o g ( " m s g " , " c a l l i n g e n d p o i n t " ) d e f e r l o g g e r . L o g ( " m s g " , " c a l l e d e n d p o i n t " ) r e t u r n n e x t ( c t x , r e q u e s t ) } } } v a r l o g g e r l o g . L o g g e r l o g g e r = l o g . N e w L o g f m t L o g g e r ( o s . S t d e r r ) l o g g e r = l o g . N e w C o n t e x t ( l o g g e r ) . W i t h ( " t s " , l o g . D e f a u l t T i m e s t a m p U T C ) u p p e r c a s e : = m a k e U p p e r c a s e E n d p o i n t ( s v c ) c o u n t : = m a k e C o u n t E n d p o i n t ( s v c ) u p p e r c a s e = l o g g i n g ( l o g . N e w C o n t e x t ( l o g g e r ) . W i t h ( " m e t h o d " , " u p p e r c a s e " ) ) ( u p p e r c a s e ) c o u n t = l o g g i n g ( l o g . N e w C o n t e x t ( l o g g e r ) . W i t h ( " m e t h o d " , " c o u n t " ) ) ( c o u n t ) / / n e t / r p c n e t R p c B i n d i n g : = N e t R p c B i n d i n g { c t x , u p p e r c a s e , c o u n t } Run
  17. package metric c o u n t e r s

    , g a u g e s , h i s t o g r a m s 에 대한 공통적인 인터페이스를 제공 e x p v a r , s t a t s d , p r o m e t h e u s 에 대한 어댑터 제공 r e q u e s t s : = m e t r i c s . N e w M u l t i C o u n t e r ( e x p v a r . N e w C o u n t e r ( " r e q u e s t s " ) , s t a t s d . N e w C o u n t e r ( i o u t i l . D i s c a r d , " r e q u e s t s _ t o t a l " , t i m e . S e c o n d ) , p r o m e t h e u s . N e w C o u n t e r ( s t d p r o m e t h e u s . C o u n t e r O p t s { N a m e s p a c e : " a d d s v c " , S u b s y s t e m : " a d d " , N a m e : " r e q u e s t s _ t o t a l " , H e l p : " T o t a l n u m b e r o f r e c e i v e d r e q u e s t s . " , } , [ ] s t r i n g { } ) , ) f u n c m e t r i c ( r e q u e s t s m e t r i c s . C o u n t e r ) e n d p o i n t . M i d d l e w a r e { r e t u r n f u n c ( n e x t e n d p o i n t . E n d p o i n t ) e n d p o i n t . E n d p o i n t { r e t u r n f u n c ( c t x c o n t e x t . C o n t e x t , r e q u e s t i n t e r f a c e { } ) ( i n t e r f a c e { } , e r r o r ) { r e q u e s t s . A d d ( 1 ) r e t u r n n e x t ( c t x , r e q u e s t ) } } }
  18. package ratelimit / / N e w T o k

    e n B u c k e t L i m i t e r r e t u r n s a n e n d p o i n t . M i d d l e w a r e t h a t a c t s a s a r a t e / / l i m i t e r b a s e d o n a t o k e n - b u c k e t a l g o r i t h m . R e q u e s t s t h a t w o u l d e x c e e d t h e / / m a x i m u m r e q u e s t r a t e a r e s i m p l y r e j e c t e d w i t h a n e r r o r . f u n c N e w T o k e n B u c k e t L i m i t e r ( t b * r a t e l i m i t . B u c k e t ) e n d p o i n t . M i d d l e w a r e { r e t u r n f u n c ( n e x t e n d p o i n t . E n d p o i n t ) e n d p o i n t . E n d p o i n t { r e t u r n f u n c ( c t x c o n t e x t . C o n t e x t , r e q u e s t i n t e r f a c e { } ) ( i n t e r f a c e { } , e r r o r ) { i f t b . T a k e A v a i l a b l e ( 1 ) = = 0 { r e t u r n n i l , E r r L i m i t e d } r e t u r n n e x t ( c t x , r e q u e s t ) } } } github.com/juju/ratelimit e = m a k e U p p e r c a s e E n d p o i n t ( s v c ) e = r a t e l i m i t . N e w T o k e n B u c k e t T h r o t t l e r ( j u j u r a t e l i m i t . N e w B u c k e t W i t h R a t e ( 1 , 1 ) , s ) ( e )
  19. package circuitbreaker f u n c H a n d

    y B r e a k e r ( c b b r e a k e r . B r e a k e r ) e n d p o i n t . M i d d l e w a r e { r e t u r n f u n c ( n e x t e n d p o i n t . E n d p o i n t ) e n d p o i n t . E n d p o i n t { r e t u r n f u n c ( c t x c o n t e x t . C o n t e x t , r e q u e s t i n t e r f a c e { } ) ( r e s p o n s e i n t e r f a c e { } , e r r e r r o r ) { i f ! c b . A l l o w ( ) { r e t u r n n i l , b r e a k e r . E r r C i r c u i t O p e n } d e f e r f u n c ( b e g i n t i m e . T i m e ) { i f e r r = = n i l { c b . S u c c e s s ( t i m e . S i n c e ( b e g i n ) ) } e l s e { c b . F a i l u r e ( t i m e . S i n c e ( b e g i n ) ) } } ( t i m e . N o w ( ) ) r e s p o n s e , e r r = n e x t ( c t x , r e q u e s t ) r e t u r n } } }
  20. package loadbalancer i m p o r t ( "

    g i t h u b . c o m / g o - k i t / k i t / l o a d b a l a n c e r " " g i t h u b . c o m / g o - k i t / k i t / l o a d b a l a n c e r / d n s s r v " ) f u n c m a i n ( ) { / / C o n s t r u c t a l o a d b a l a n c e r f o r f o o s v c , w h i c h g e t s f o o s v c i n s t a n c e s b y / / p o l l i n g a s p e c i f i c D N S S R V n a m e . p : = d n s s r v . N e w P u b l i s h e r ( " f o o s v c . i n t e r n a l . d o m a i n " , 5 * t i m e . S e c o n d , f o o F a c t o r y , l o g g e r ) l b : = l o a d b a l a n c e r . N e w R o u n d R o b i n ( p ) / / G e t a n e w e n d p o i n t f r o m t h e l o a d b a l a n c e r . e n d p o i n t , e r r : = l b . E n d p o i n t ( ) i f e r r ! = n i l { p a n i c ( e r r ) } / / U s e t h e e n d p o i n t t o m a k e a r e q u e s t . r e s p o n s e , e r r : = e n d p o i n t ( c t x , r e q u e s t ) } f u n c f o o F a c t o r y ( i n s t a n c e s t r i n g ) ( e n d p o i n t . E n d p o i n t , e r r o r ) { / / C o n v e r t a n i n s t a n c e ( h o s t : p o r t ) t o a n e n d p o i n t , v i a a d e f i n e d t r a n s p o r t b i n d i n g . }
  21. f u n c m a i n ( )

    { p : = d n s s r v . N e w P u b l i s h e r ( " f o o s v c . i n t e r n a l . d o m a i n " , 5 * t i m e . S e c o n d , f o o F a c t o r y , l o g g e r ) l b : = l o a d b a l a n c e r . N e w R o u n d R o b i n ( p ) e n d p o i n t : = l o a d b a l a n c e r . R e t r y ( 3 , 5 * t i m e . S e c o n d s , l b ) r e s p o n s e , e r r : = e n d p o i n t ( c t x , r e q u e s t ) / / r e q u e s t s w i l l b e a u t o m a t i c a l l y l o a d b a l a n c e d } 현재 d n s s r v 와 s t a t i c 지원 c o n s u l , e t c d , z o o k e e p e r 등 지원 예정
  22. package tracing f u n c A n n o

    t a t e S e r v e r ( n e w S p a n N e w S p a n F u n c , c C o l l e c t o r ) e n d p o i n t . M i d d l e w a r e { r e t u r n f u n c ( n e x t e n d p o i n t . E n d p o i n t ) e n d p o i n t . E n d p o i n t { r e t u r n f u n c ( c t x c o n t e x t . C o n t e x t , r e q u e s t i n t e r f a c e { } ) ( i n t e r f a c e { } , e r r o r ) { s p a n , o k : = f r o m C o n t e x t ( c t x ) i f ! o k { s p a n = n e w S p a n ( n e w I D ( ) , n e w I D ( ) , 0 ) c t x = c o n t e x t . W i t h V a l u e ( c t x , S p a n C o n t e x t K e y , s p a n ) } s p a n . A n n o t a t e ( S e r v e r R e c e i v e ) d e f e r f u n c ( ) { s p a n . A n n o t a t e ( S e r v e r S e n d ) ; c . C o l l e c t ( s p a n ) } ( ) r e t u r n n e x t ( c t x , r e q u e s t ) } } } / / S e r v e r - s i d e v a r s e r v e r e n d p o i n t . E n d p o i n t s e r v e r = m a k e E n d p o i n t ( ) / / f o r y o u r s e r v i c e s e r v e r = z i p k i n . A n n o t a t e S e r v e r ( s p a n F u n c , c o l l e c t o r ) ( s e r v e r ) g o s e r v e V i a H T T P ( s e r v e r ) A p p d a s h 은 계획중