$30 off During Our Annual Pro Sale. View Details »

軽量デバッグツールPostmortemの紹介.pdf

OHTA Shogo
September 26, 2019

 軽量デバッグツールPostmortemの紹介.pdf

OHTA Shogo

September 26, 2019
Tweet

More Decks by OHTA Shogo

Other Decks in Programming

Transcript

  1. ܰྔσόοάπʔϧ
    1PTUNPSUFNͷ঺հ
    -JTQNFFUVQ
    !BUIPT

    View Slide

  2. طଘͷओͳσόοάख๏
    ‣ QSJOUσόοά
    QSO΍QSJOUMOΛૠೖ͠ɺͦͷ࣌఺ͷ஋Λ֬ೝͨ͠Γͦͷίʔυ͕࣮ߦ͞Εͨ
    ͜ͱΛ֬ೝ͢Δ
    ૉ๿͕ͩखܰͳख๏ͰɺσόοΨ͕࢖͑ͳ͍৔߹ʹ༗ޮͳ͜ͱ΋ଟ͍
    ‣ τϨʔεػೳ
    ؔ਺ݺͼग़͠ͷҾ਺΍໭Γ஋ɺݺͼग़͠ͷਂ͞౳Λग़ྗ͢Δ
    UPPMTUSBDF΍$*%&3ͷτϨʔεػೳ౳ͱͯ͠ఏڙ͞ΕΔ
    ‣ σόοΨ
    ϒϨʔΫϙΠϯτΛઃఆͯ͠ϓϩάϥϜͷ࣮ߦΛఀࢭ͠ɺεςοϓ࣮ߦ΍
    ϩʔΧϧ؀ڥͷΠϯεϖΫτ౳͕Ͱ͖Δ
    ৚͖݅ͭͷϒϨʔΫϙΠϯτΛઃఆͯ͠৚݅Λຬͨ͢৔߹͚࣮ͩߦΛࢭΊΔ

    View Slide

  3. طଘख๏͕ద༻ͮ͠Β͍έʔε
    ‣ ಉ͡ॲཧ͕ ϧʔϓ΍࠶ؼͰ
    Կ౓΋܁Γฦ࣮͠ߦ͞ΕΔ
    QSJOUσόοά΍τϨʔεػೳͷग़ྗ͕ଟ͘ͳΓɺॏཁͳग़ྗͷಛఆ͕೉͘͠ͳΔ
    ৚͖݅ͭϒϨʔΫϙΠϯτΛ͏·͘ઃఆ͠ͳ͍ͱԿ౓΋໰୊ͱ௚઀ؔ܎ͳ͍ճͷ܁Γ
    ฦ͠Ͱ࣮ߦ͕ࢭ·Δ
    ‣ ܁Γฦ͠ͷ݁Ռ͕ޙͷ܁Γฦ͠ʹӨڹΛ༩͑Δ
    ໰୊͕ى͖ΔԿճ͔લͷ܁Γฦ͕͠໰୊ͷݪҼʹͳΓ͏Δ
    ໰୊͕͋Δͱ෼͔Δ࣌఺Ͱ࣮ߦΛϒϨʔΫͯ͠΋ͦ͜ʹ໰୊ͷݪҼ͕ͳ͘ɺͦͷԿճ
    ͔લͷ܁Γฦ͠ͷঢ়ଶΛͲ͏ʹ͔ಛఆ͢Δඞཁ͕͋Δ
    ‣ ϚϧνεϨουͷॲཧ͕བྷΉͱ͞Βʹ໽հ
    ‣ ྫ
    ࣌ؒܦաʹ͕͍ͨ͠ϦΞϧλΠϜʹঢ়ଶ͕มԽ͢Δ΋ͷ ήʔϜɺΞχϝʔγϣϯ

    ݴޠॲཧܥ
    ͱʹ͔͘ೖྗͷαΠζ͕େ͖͍ू໿ॲཧ FUD

    View Slide

  4. 1PTUNPSUFN
    ‣ খ͞ͳσόοάࢧԉπʔϧ
    ‣ ࣮ߦதͷ஋Λه࿥͠ɺࣄޙݕূ͢ΔͨΊͷ༻్Ͱ࢖͏
    ‣ ϩάʹͲ͏͍͏஋ΛͲ͏ه࿥͢Δ͔Λτϥϯεσϡʔαʹ
    ΑͬͯॊೈʹΧελϚΠζͰ͖Δ
    ‣ ݸผͷηογϣϯΛ࡞Δ͜ͱʹΑΓɺଞͷϩά͔Β෼཭
    ͞ΕͨϩάΛͱΔ͜ͱ͕Ͱ͖Δ

    View Slide

  5. 1PTUNPSUFNͷجຊతͳ࢖͍ํ

    ‣ pm/saveݺͼग़͠ຖͷϩʔΧϧ؀ڥΛϚοϓͱͯ͠ه࿥͢Δ
    ‣ pm/log-forࢦఆͨ͠ΩʔͰه࿥͞ΕͨϩάΛฦ͢
    (require '[postmortem.core :as pm])
    (defn sum [n]
    (loop [n n sum 0]
    (pm/save :sum)
    (if (= n 0)
    sum
    (recur (dec n) (+ sum n)))))
    (sum 5) ;=> 15
    (pm/log-for :sum)
    ;=> [{:n 5 :sum 0} {:n 4 :sum 5} {:n 3 :sum 9}
    {:n 2 :sum 12} {:n 1 :sum 14} {:n 0 :sum 15}]

    View Slide

  6. 1PTUNPSUFNͷجຊతͳ࢖͍ํ

    ‣ pm/spy>>ݺͼग़͠ຖʹҾ਺ʹ౉ͨ͠஋Λه࿥͢Δ
    ‣ pm/logsه࿥͞Εͨ͢΂ͯͷϩάΛฦ͢
    (require '[postmortem.core :as pm])
    (defn sum [n]
    (loop [n n sum 0]
    (if (= n 0)
    sum
    (recur (dec n)
    (pm/spy>> :sum-val (+ sum n)))))
    (sum 5) ;=> 15
    (pm/log-for :sum-val) ;=> [5 9 12 14 15]
    (pm/logs) ;=> {:sum [{:n 5 :sum 0} {:n 4 :sum 5} …]
    :sum-val [5 9 12 14 15]}

    View Slide

  7. 1PTUNPSUFNͷجຊతͳ࢖͍ํ

    ‣ pm/log-for ΍pm/logs ͰऔΓग़ͨ͠ϩάͷ݁Ռ͸
    pm/reset! ౳ͰϦηοτ͢Δ·Ͱ্ॻ͖͞Εͳ͍
    (require '[postmortem.core :as pm])
    (sum 100) ;=> 5050
    (pm/log-for :sum-val) ;=> [5 9 12 14 15]
    (pm/logs) ;=> {:sum [{:n 5 :sum 0} {:n 4 :sum 5} …]
    :sum-val [5 9 12 14 15]}
    (pm/reset!)
    (pm/logs) ;=> {}
    (sum 3) ;=> 6
    (pm/logs) ;=> {:sum [{:n 3 :sum 0} {:n 2 :sum 1} …]
    :sum-val [3 5 6]}

    View Slide

  8. τϥϯεσϡʔαͱͷ࿈ܞ

    ‣ pm/save ΍pm/spy>> ͸τϥϯεσϡʔαΛΦϓγϣφϧ
    Ҿ਺ͱͯ͠औΕɺϩάΛͲ͏ه࿥͢Δ͔ΛΧελϚΠζͰ͖Δ
    (require '[postmortem.core :as pm])
    (defn sum [n]
    (loop [n n sum 0]
    (pm/save :sum (filter #(even? (:n %))))
    (if (= n 0)
    sum
    (recur (dec n) (+ sum n)))))
    (sum 5) ;=> 15
    (pm/log-for :sum)
    ;=> [{:n 4 :sum 5} {:n 2 :sum 12} {:n 0 :sum 15}]

    View Slide

  9. τϥϯεσϡʔαͱͷ࿈ܞ

    ‣ map-indexed Ͱ࿈൪ΛৼͬͨΓɺrandom-sample Ͱ
    ϥϯμϜαϯϓϦϯάΛͨ͠Γ΋Ͱ͖Δ
    (require '[postmortem.core :as pm])
    (defn sum [n]
    (loop [n n sum 0]
    (pm/save :sum
    (comp (map-indexed #(assoc %2 :id %1))
    (random-sample 0.5))
    (if (= n 0)
    sum
    (recur (dec n) (+ sum n)))))
    (sum 5) ;=> 15
    (pm/log-for :sum)
    ;=> [{:n 5 :sum 0 :id 0} {:n 4 :sum 5 :id 1}
    {:n 1 :sum 14 :id 4}]

    View Slide

  10. τϥϯεσϡʔαͱͷ࿈ܞ

    ‣ System/nanoTimeͰݺͼग़࣌͠ࠁΛ͚͓͍ͭͯͯɺxf/
    debounceͰҰఆִؒͷ࣌ؒ಺ͷϩάΛؒҾ͘͜ͱ΋Ͱ͖Δ
    (require '[postmortem.core :as pm]
    '[postmortem.xforms :as xf])
    (defn sum [n]
    (loop [n n sum 0]
    (pm/save :sum
    (comp (map #(assoc % :t (System/nanoTime)))
    (xf/debounce :t 10000))
    (if (= n 0)
    sum
    (recur (dec n) (+ sum n)))))
    (sum 10) ;=> 55
    (pm/log-for :sum)
    ;=> [{:n 10 :sum 0 :t 105365222743711} {:n 9 :sum 10 :t 105365222775129}
    {:n 7 :sum 27 :t 105365222789449} {:n 4 :sum 45 :t 105365222802184}
    {:n 1 :sum 54 :t 105365222813741}]

    View Slide

  11. τϥϯεσϡʔαͱͷ࿈ܞ

    ‣ take-whileͰ৚݅Λຬͨؒ͢ͷϩά͚ͩΛ࢒ͨ͠Γɺ
    xf/take-lastͰ࠷ޙͷ/ݸͷϩά͚ͩΛ࢒ͨ͠Γ΋Ͱ͖Δ
    (require '[postmortem.core :as pm]
    '[postmortem.xforms :as xf])
    (defn sum [n]
    (loop [n n sum 0]
    (pm/save :sum
    (comp (take-while #(< (:sum %) 1000))
    (xf/take-last 3))
    (if (= n 0)
    sum
    (recur (dec n) (+ sum n)))))
    (sum 100) ;=> 5050
    (pm/log-for :sum)
    ;=> [{:n 92 :sum 772} {:n 91 :sum 864} {:n 90 :sum 955}]

    View Slide

  12. xf/take-lastͷ࣮૷
    ‣ τϥϯεσϡʔα͸ͭͷॲཧ͔ΒͳΔ
    ॳظԽॲཧεςοϓॲཧ׬ྃॲཧ
    ‣ xf/take-last ͸εςοϓॲཧͰೖྗΛϦϯάόοϑΝʹ٧Ίͯɺ
    ׬ྃॲཧͰόοϑΝʹ࢒͍ͬͯΔཁૉΛʮ࠷ޙͷ/ݸʯͱͯ֬͠ఆ͢Δ
    (defn take-last [^long n]
    (fn [rf]
    (let [idx (volatile! 0), vals (object-array n)]
    (fn
    ([] (rf))
    ([result]
    (let [offset (if (>= @idx n) (long @idx) 0)]
    (transduce (map #(aget vals
    (rem (+ % offset) n)))
    rf result (range n))))
    ([acc input]
    (aset vals (rem @idx n) input)
    (vswap! idx inc)
    acc)))))
    ॳظԽॲཧ
    ׬ྃॲཧ
    εςοϓॲཧ

    View Slide

  13. τϥϯεσϡʔαͷ׬ྃॲཧ͸͍ͭݺ͹ΕΔͷ͔ʁ
    (defn add [x y]
    (pm/save :add (comp (map (fn [x] (prn [:pre x]) x))
    (xf/take-last 3)
    (map (fn [x] (prn [:post x]) x))))
    (+ x y))
    (redue add 0 (range 5))
    ;; [:pre {:x 0, :y 0}]
    ;; [:pre {:x 0, :y 1}]
    ;; [:pre {:x 1, :y 2}]
    ;; [:pre {:x 3, :y 3}]
    ;; [:pre {:x 6, :y 4}]
    ;=> 10
    (pm/logs)
    ;; [:post {:x 1, :y 2}]
    ;; [:post {:x 3, :y 3}]
    ;; [:post {:x 6, :y 4}]
    ;=> {:add [{:x 1, :y 2} {:x 3, :y 3} {:x 6, :y 4}]}
    (pm/logs)
    ;=> {:add [{:x 1, :y 2} {:x 3, :y 3} {:x 6, :y 4}]}

    View Slide

  14. τϥϯεσϡʔαͷ׬ྃॲཧ͸͍ͭݺ͹ΕΔͷ͔ʁ
    ‣ ϩάΛࢀরͱͨ͠௚લʹճ͚ͩ׬ྃॲཧ͕࣮ߦ͞ΕΔΑ
    ͏ʹͳ͍ͬͯΔ
    ‣ Ұ୴׬ྃॲཧΛͨ͠ϩάΛ͞Βʹߋ৽Ͱ͖ͯ͠·͏ͱΑ
    ͘෼͔Βͳ͍ڍಈʹͳΓ͏ΔͷͰɺpm/logs౳ͰϩάΛ
    ࢀরͨ͠Βpm/reset!౳ͰϦηοτ͢Δ·Ͱߋ৽Ͱ͖
    ͳ͍࢓༷ʹͳ͍ͬͯΔ

    View Slide

  15. ηογϣϯʹΑΔϩάͷ෼཭
    ‣ ηογϣϯ͸Ұ࿈ͷϩάͷอଘઌ
    ‣ ৽͍͠ηογϣϯΛ࡞Δ͜ͱͰଞͷϩάͱͷ෼཭͕Ͱ͖Δ
    (require '[postmortem.core :as pm])
    (def sess1 (pm/make-session))
    (def sess2 (pm/make-session))
    (let [f0 (fn [n] (pm/save :f))
    f1 (fn [n] (pm/save sess1 :f identity))
    f2 (fn [n] (pm/save sess2 :f identity))]
    (f0 1) (f1 10) (f2 100)
    (f0 2) (f1 20) (f2 200))
    (pm/logs) ;=> {:f [{:n 1} {:n 2}]}
    ;; ↑͸ (pm/logs (pm/current-session)) ͱಉ͡
    (pm/logs sess1) ;=> {:f [{:n 10} {:n 20}]}
    (pm/logs sess2) ;=> {:f [{:n 100} {:n 200}]}

    View Slide

  16. ݱࡏͷηογϣϯ
    ‣ pm/set-current-session!ݱࡏͷηογϣϯΛมߋ
    ‣ pm/with-sessionϚΫϩຊମ಺ͷΈݱࡏͷηογϣϯΛมߋ
    (require '[postmortem.core :as pm])
    (defn add [x y] (pm/save :add) (+ x y))
    (def sess1 (pm/make-session))
    (pm/set-current-session! sess1)
    (add 1 2) ;=> 3
    (def sess2 (pm/make-session))
    (pm/with-session sess2
    (add 3 4)) ;=> 7
    (pm/log-for sess1 :add) ;=> [{:x 1 :y 2}]
    (pm/log-for sess2 :add) ;=> [{:x 3 :y 4}]

    View Slide

  17. ηογϣϯͱτϥϯεσϡʔα
    ‣ ηογϣϯʹτϥϯεσϡʔαΛ࣋ͨͤΔ͜ͱ͕Ͱ͖ɺͦͷ
    ηογϣϯΛ࢖͏͢΂ͯͷpm/save౳ʹͦΕ͕ద༻͞ΕΔ
    (require '[postmortem.core :as pm])
    (defn add [x y] (pm/save :add) (+ x y))
    (def sess
    (pm/make-session (map (fn [x] (prn 'Logging x) x))))
    (pm/set-current-session! sess)
    (add 1 2)
    ;; Logging {:x 1 :y 2}
    ;=> 3
    (add 3 4)
    ;; Logging {:x 3 :y 4}
    ;=> 7

    View Slide

  18. ಉظతηογϣϯ
    ‣ pm/make-sessionͰ࡞ΒΕΔηογϣϯ͸εϨουηʔϑͰͳ͍
    ‣ pm/make-synchronized-sessionͰ࡞ΒΕΔηογϣϯ΁ͷมߋ͸ಉظ͞ΕΔ
    (require '[postmortem.core :as pm])
    (defn f [x]
    (pm/save :f (comp (map-indexed #(assoc %2 :i %1))
    (xf/take-last))))
    (defn test []
    (run! deref [(future (dotimes [i 10000] (f i)))
    (future (dotimes [i 10000] (f i)))]))
    (test)
    (pm/log-for :f) ;=> [{:n 9999, :i 19982}]
    (pm/set-current-session! (pm/make-synchronized-session))
    (test)
    (pm/log-for :f) ;=> [{:n 9999, :i 19999}]

    View Slide

  19. ·ͱΊ
    ‣ ैདྷͷσόοάख๏Ͱσόοάͮ͠Β͍έʔεʹରԠͨ͠
    1PTUNPSUFNͱ͍͏σόοάπʔϧΛ։ൃͨ͠
    ‣ τϥϯεσϡʔαͱͷ࿈ܞʹΑΓɺϩάʹͲ͏͍͏஋ΛͲ
    ͏ه࿥͢Δ͔ΛॊೈʹΧελϚΠζͰ͖ΔΑ͏ʹͳͬͨ
    ‣ ηογϣϯͷ֓೦Λಋೖͨ͜͠ͱͰɺϚϧνεϨουͰͷ
    σόοάͰ΋࢖͑ΔΑ͏ʹͳͬͨ

    View Slide

  20. IUUQTHJUIVCDPNBUIPTQPTUNPSUFN

    View Slide