Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

モバイルアプリの行動ログの「仕込み」を快適にする / iOSDC Japan 2022 - ...

Yuji Fujisaka
September 12, 2022

モバイルアプリの行動ログの「仕込み」を快適にする / iOSDC Japan 2022 - Mobile App Logging

iOSDC Japan 2022、9/12(月) 13:55〜 Track B での発表内容です
https://fortee.jp/iosdc-japan-2022/proposal/ad544d2d-0e37-48f7-836a-3d46abe4ad2f

動画
https://youtu.be/4NGvI9PoAIQ?list=PLod2oSGQp3W6tx5JMQntpuZ-fNpP4Y_Hh

クックパッドの After Party についてhttps://cookpad.connpass.com/event/254459/

Yuji Fujisaka

September 12, 2022
Tweet

More Decks by Yuji Fujisaka

Other Decks in Programming

Transcript

  1. ߦಈϩάͷ࣮૷ ྫɿ(PPHMF"OBMZUJDT 'JSFCBTF IUUQTpSFCBTFHPPHMFDPNEPDTBOBMZUJDTFWFOUT Analytics.logEvent("select_content", parameters: [ "content_type": "image", "content_id":

    "P12453", "items": [["name": "Kittens"]] ]) ෼ੳʹඞཁͳ৘ใʢྫɿΠϕϯτ໊ɺίϯςϯπͷछྨɺ*%౳ʣΛϩΨʔͰૹ৴
  2. υΩϡϝϯτϕʔεͷܕ҆શͳϩά࣮૷ίʔυࣗಈੜ੒ ֓ཁ wϩάఆٛυΩϡϝϯτʢ.BSLEPXOʣ͔Β ϩά࣮૷ίʔυʢ4XJGUʣΛࣗಈੜ੒ τϥϯεύΠϧ # recipe_search Ϩγϐݕࡧը໘ͷΠϕϯτͰ͢ ## search

    ϨγϐݕࡧΛߦͬͨࡍʹૹ෇͞Ε·͢ - keyword: !string 256 - ݕࡧΩʔϫʔυ - order: SearchOrder - ݕࡧॱ - latest,popularity ## show_recipe ݕࡧ݁Ռը໘͔ΒϨγϐৄࡉը໘ʹભҠ͢Δࡍʹૹ෇͞Ε·͢ - recipe_id: !integer - දࣔͨ͠ϨγϐͷID /// Ϩγϐݕࡧը໘ͷΠϕϯτͰ͢ public enum RecipeSearch: LogCategory { public static var categoryName: String { "recipe_search" } public var eventName: String { switch self { case .search: return "search" case .showRecipe: return "show_recipe" } } public func makePayload() -> [String: Any] { switch self { case let .search(keyword, order): return [ "keyword": keyword.validateLength(within: 256).dump(), "order": order.dump(), ].compactMapValues { $0 } case let .showRecipe(recipeId): return [ "recipe_id": recipeId.dump(), ].compactMapValues { $0 } } } /// ϨγϐݕࡧΛߦͬͨࡍʹૹ෇͞Ε·͢ case search(keyword: String, order: SearchOrder) /// ݕࡧ݁Ռը໘͔ΒϨγϐৄࡉը໘ʹભҠ͢Δࡍʹૹ෇͞Ε·͢ case showRecipe(recipeId: Int64) } ਓ͕ॻ͍ͨ.BSLEPXOܗࣜͷυΩϡϝϯτ ࣗಈੜ੒͞ΕΔ4XJGUͷίʔυ The Swift logo is a trademark of Apple Inc. https://developer.apple.com/swift/resources/ The Markdown Mark https://github.com/dcurtis/markdown-mark
  3. υΩϡϝϯτϕʔεͷܕ҆શͳϩά࣮૷ίʔυࣗಈੜ੒ ۩ମྫ खॱ ɹϩά࢓༷Λߟ͑ͯ ɹυΩϡϝϯτΛهड़ ɹ # recipe_search Ϩγϐݕࡧը໘ͷΠϕϯτͰ͢ ##

    search ϨγϐݕࡧΛߦͬͨࡍʹૹ෇͞Ε·͢ - keyword: !string 256 - ݕࡧΩʔϫʔυ - order: SearchOrder - ݕࡧॱ - latest,popularity ## show_recipe ݕࡧ݁Ռը໘͔ΒϨγϐৄࡉը໘ʹભҠ͢Δࡍʹૹ෇͞Ε·͢ - recipe_id: !integer - දࣔͨ͠ϨγϐͷID
  4. υΩϡϝϯτϕʔεͷܕ҆શͳϩά࣮૷ίʔυࣗಈੜ੒ ۩ମྫ खॱ ɹϩά࢓༷Λߟ͑ͯ ɹυΩϡϝϯτΛهड़ ɹ # recipe_search Ϩγϐݕࡧը໘ͷΠϕϯτͰ͢ ##

    search ϨγϐݕࡧΛߦͬͨࡍʹૹ෇͞Ε·͢ - keyword: !string 256 - ݕࡧΩʔϫʔυ - order: SearchOrder - ݕࡧॱ - latest,popularity ## show_recipe ݕࡧ݁Ռը໘͔ΒϨγϐৄࡉը໘ʹભҠ͢Δࡍʹૹ෇͞Ε·͢ - recipe_id: !integer - දࣔͨ͠ϨγϐͷID ## search ϨγϐݕࡧΛߦͬͨࡍʹૹ෇͞Ε·͢ - keyword: !string 256 - ݕࡧΩʔϫʔυ - order: SearchOrder - ݕࡧॱ - latest, popularity
  5. खॱ εΫϦϓτΛ࣮ߦ ˠ9DPEFϓϩδΣΫτ಺ʹ ɹίʔυ͕ࣗಈੜ੒͞ΕΔ  υΩϡϝϯτϕʔεͷܕ҆શͳϩά࣮૷ίʔυࣗಈੜ੒ ۩ମྫ /// Ϩγϐݕࡧը໘ͷΠϕϯτͰ͢ public

    enum RecipeSearch: LogCategory { public static var categoryName: String { "recipe_search" } public var eventName: String { switch self { case .search: return "search" case .showRecipe: return "show_recipe" } } public func makePayload() -> [String: Any] { switch self { case let .search(keyword, order): return [ "keyword": keyword.validateLength(within: 256).dump(), "order": order.dump(), ].compactMapValues { $0 } case let .showRecipe(recipeId): return [ "recipe_id": recipeId.dump(), ].compactMapValues { $0 } } } /// ϨγϐݕࡧΛߦͬͨࡍʹૹ෇͞Ε·͢ case search(keyword: String, order: SearchOrder) /// ݕࡧ݁Ռը໘͔ΒϨγϐৄࡉը໘ʹભҠ͢Δࡍʹૹ෇͞Ε·͢ case showRecipe(recipeId: Int64) }
  6. खॱ εΫϦϓτΛ࣮ߦ ˠ9DPEFϓϩδΣΫτ಺ʹ ɹίʔυ͕ࣗಈੜ੒͞ΕΔ  υΩϡϝϯτϕʔεͷܕ҆શͳϩά࣮૷ίʔυࣗಈੜ੒ ۩ମྫ /// Ϩγϐݕࡧը໘ͷΠϕϯτͰ͢ public

    enum RecipeSearch: LogCategory { public static var categoryName: String { "recipe_search" } public var eventName: String { switch self { case .search: return "search" case .showRecipe: return "show_recipe" } } public func makePayload() -> [String: Any] { switch self { case let .search(keyword, order): return [ "keyword": keyword.validateLength(within: 256).dump(), "order": order.dump(), ].compactMapValues { $0 } case let .showRecipe(recipeId): return [ "recipe_id": recipeId.dump(), ].compactMapValues { $0 } } } /// ϨγϐݕࡧΛߦͬͨࡍʹૹ෇͞Ε·͢ case search(keyword: String, order: SearchOrder) /// ݕࡧ݁Ռը໘͔ΒϨγϐৄࡉը໘ʹભҠ͢Δࡍʹૹ෇͞Ε·͢ case showRecipe(recipeId: Int64) } NBLFίϚϯυ
  7. खॱ εΫϦϓτΛ࣮ߦ ˠ9DPEFϓϩδΣΫτ಺ʹ ɹίʔυ͕ࣗಈੜ੒͞ΕΔ  υΩϡϝϯτϕʔεͷܕ҆શͳϩά࣮૷ίʔυࣗಈੜ੒ ۩ମྫ /// Ϩγϐݕࡧը໘ͷΠϕϯτͰ͢ public

    enum RecipeSearch: LogCategory { public static var categoryName: String { "recipe_search" } public var eventName: String { switch self { case .search: return "search" case .showRecipe: return "show_recipe" } } public func makePayload() -> [String: Any] { switch self { case let .search(keyword, order): return [ "keyword": keyword.validateLength(within: 256).dump(), "order": order.dump(), ].compactMapValues { $0 } case let .showRecipe(recipeId): return [ "recipe_id": recipeId.dump(), ].compactMapValues { $0 } } } /// ϨγϐݕࡧΛߦͬͨࡍʹૹ෇͞Ε·͢ case search(keyword: String, order: SearchOrder) /// ݕࡧ݁Ռը໘͔ΒϨγϐৄࡉը໘ʹભҠ͢Δࡍʹૹ෇͞Ε·͢ case showRecipe(recipeId: Int64) } NBLFίϚϯυ ϩάఆٛͷྻڍܕʢFOVNʣɹ
  8. खॱ εΫϦϓτΛ࣮ߦ ˠ9DPEFϓϩδΣΫτ಺ʹ ɹίʔυ͕ࣗಈੜ੒͞ΕΔ  υΩϡϝϯτϕʔεͷܕ҆શͳϩά࣮૷ίʔυࣗಈੜ੒ ۩ମྫ /// Ϩγϐݕࡧը໘ͷΠϕϯτͰ͢ public

    enum RecipeSearch: LogCategory { public static var categoryName: String { "recipe_search" } public var eventName: String { switch self { case .search: return "search" case .showRecipe: return "show_recipe" } } public func makePayload() -> [String: Any] { switch self { case let .search(keyword, order): return [ "keyword": keyword.validateLength(within: 256).dump(), "order": order.dump(), ].compactMapValues { $0 } case let .showRecipe(recipeId): return [ "recipe_id": recipeId.dump(), ].compactMapValues { $0 } } } /// ϨγϐݕࡧΛߦͬͨࡍʹૹ෇͞Ε·͢ case search(keyword: String, order: SearchOrder) /// ݕࡧ݁Ռը໘͔ΒϨγϐৄࡉը໘ʹભҠ͢Δࡍʹૹ෇͞Ε·͢ case showRecipe(recipeId: Int64) } NBLFίϚϯυ ϩάఆٛͷྻڍܕʢFOVNʣɹ /// Ϩγϐݕࡧը໘ͷΠϕϯτͰ͢ public enum RecipeSearch: LogCategory { ʢதུʣ ɹ /// ϨγϐݕࡧΛߦͬͨࡍʹૹ෇͞Ε·͢ case search(keyword: String, order: SearchOrder) /// ݕࡧ݁Ռը໘͔ΒϨγϐৄࡉը໘ʹભ…… case showRecipe(recipeId: Int64) }
  9. ઃܭ ࣮૷ ޮՌଌఆ ҙࢥܾఆ ϦϦʔε ݕূ໨తͷ ੔ཧɾ೺Ѳ ϩάఆٛ ϩά࣮૷ #ة͏͍

    ಈ࡞֬ೝ 0,✅ νΣοΫϦετ͕ࣗಈͰຒ·ΔΞϓϦ಺ϩά֬ೝπʔϧ ಋೖલ ͜ͷύλʔϯͰ͸ ɹߟྀ࿙Εͯͨͳʜʜ
  10. ઃܭ ࣮૷ ޮՌଌఆ ҙࢥܾఆ ϦϦʔε ݕূ໨తͷ ੔ཧɾ೺Ѳ ϩάఆٛ ϩά࣮૷ 0,✅

    ಈ࡞֬ೝ νΣοΫϦετ͕ࣗಈͰຒ·ΔΞϓϦ಺ϩά֬ೝπʔϧ ಋೖޙ
  11. ઃܭ ࣮૷ ޮՌଌఆ ҙࢥܾఆ ϦϦʔε ࣮૷ऀҎ֎ʹ΋ ෼୲Ͱ͖ͯॿ͔Δ% ݕূ໨తͷ ੔ཧɾ೺Ѳ ϩάఆٛ

    ϩά࣮૷ 0,✅ ಈ࡞֬ೝ νΣοΫϦετ͕ࣗಈͰຒ·ΔΞϓϦ಺ϩά֬ೝπʔϧ ಋೖޙ
  12. ΞϓϦͷϩά࣮૷ͷؔ࿈ਤ ϩάఆٛ .BSLEPXO 04-PH 04-PH4UPSF ΞϓϦ಺ ϩά֬ೝπʔϧ ϩάఆٛ 4XJGU ϩάૹ৴ϥΠϒϥϦ

    PT-PHHFS ϩΨʔ 04ϩάʹ΋ग़ྗ ϩάαʔόʔ΁ૹ৴ ఆٛΛ࢖ͬͯૹ৴ .BSLEPXO ύʔαʔ EBJGVLV τϥϯεύΠϥ ఆٛΛ ࢀর 04ϩάΛऔಘ தؒදݱΛ 4XJGU ίʔυԽ ʢ։ൃ൛ΞϓϦͷΈʣ
  13. ΞϓϦͷϩά࣮૷ͷؔ࿈ਤ ϩάఆٛ .BSLEPXO 04-PH 04-PH4UPSF ΞϓϦ಺ ϩά֬ೝπʔϧ ϩάఆٛ 4XJGU ϩάૹ৴ϥΠϒϥϦ

    PT-PHHFS ϩΨʔ 04ϩάʹ΋ग़ྗ ϩάαʔόʔ΁ૹ৴ ఆٛΛ࢖ͬͯૹ৴ .BSLEPXO ύʔαʔ EBJGVLV τϥϯεύΠϥ ఆٛΛ ࢀর 04ϩάΛऔಘ தؒදݱΛ 4XJGU ίʔυԽ ʢ։ൃ൛ΞϓϦͷΈʣ
  14. ΞϓϦͷϩά࣮૷ͷؔ࿈ਤ ϩάఆٛ .BSLEPXO 04-PH 04-PH4UPSF ΞϓϦ಺ ϩά֬ೝπʔϧ ϩάఆٛ 4XJGU ϩάૹ৴ϥΠϒϥϦ

    PT-PHHFS ϩΨʔ 04ϩάʹ΋ग़ྗ ϩάαʔόʔ΁ૹ৴ ఆٛΛ࢖ͬͯૹ৴ .BSLEPXO ύʔαʔ EBJGVLV τϥϯεύΠϥ ఆٛΛ ࢀর 04ϩάΛऔಘ தؒදݱΛ 4XJGU ίʔυԽ ʢ։ൃ൛ΞϓϦͷΈʣ
  15. ΞϓϦͷϩά࣮૷ͷؔ࿈ਤ ϩάఆٛ .BSLEPXO 04-PH 04-PH4UPSF ΞϓϦ಺ ϩά֬ೝπʔϧ ϩάఆٛ 4XJGU ϩάૹ৴ϥΠϒϥϦ

    PT-PHHFS ϩΨʔ 04ϩάʹ΋ग़ྗ ϩάαʔόʔ΁ૹ৴ ఆٛΛ࢖ͬͯૹ৴ .BSLEPXO ύʔαʔ EBJGVLV τϥϯεύΠϥ ఆٛΛ ࢀর 04ϩάΛऔಘ தؒදݱΛ 4XJGU ίʔυԽ ʢ։ൃ൛ΞϓϦͷΈʣ
  16. ΞϓϦͷϩά࣮૷ͷؔ࿈ਤ ϩάఆٛ .BSLEPXO 04-PH 04-PH4UPSF ΞϓϦ಺ ϩά֬ೝπʔϧ ϩάఆٛ 4XJGU ϩάૹ৴ϥΠϒϥϦ

    PT-PHHFS ϩΨʔ 04ϩάʹ΋ग़ྗ ϩάαʔόʔ΁ૹ৴ ఆٛΛ࢖ͬͯૹ৴ .BSLEPXO ύʔαʔ EBJGVLV τϥϯεύΠϥ ఆٛΛ ࢀর 04ϩάΛऔಘ தؒදݱΛ 4XJGU ίʔυԽ ʢ։ൃ൛ΞϓϦͷΈʣ
  17. PT-PHHFS ֓ཁ J04 w ΞϓϦ͔Β౷߹ϩάγεςϜʹϩάΛॻ͖ࠐΊΔ w ඇৗʹޮ཰తͰɺΞϓϦͷಈ࡞஗Ԇͳ͘࢖͑Δ w $POTPMFBQQ΍9DPEFͷίϯιʔϧͰϩάΛ֬ೝͰ͖Δ w

    ηϯγςΟϒͳ৘ใ͸ϚεΫͰ͖Δʢࢦఆͯ͠ެ։΋Ͱ͖Δʣ w IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOPTMPHHFS w IUUQTEFWFMPQFSBQQMFDPNWJEFPTQMBZXXED
  18. PT-PHHFS ؆୯ͳྫ import os // ϩάͷग़͕ࣗ෼͔ΔΑ͏ʹ subsystem ͱ category Λࢦఆ

    let osLogger = Logger(subsystem: bundleID, category: "Activity") // ϩάΛॻ͖ࠐΉ osLogger.notice(“\(logDataString)”) J04
  19. ΞϓϦͷϩά࣮૷ͷؔ࿈ਤ ϩάఆٛ .BSLEPXO 04-PH 04-PH4UPSF ΞϓϦ಺ ϩά֬ೝπʔϧ ϩάఆٛ 4XJGU ϩάૹ৴ϥΠϒϥϦ

    PT-PHHFS ϩΨʔ 04ϩάʹ΋ग़ྗ ϩάαʔόʔ΁ૹ৴ ఆٛΛ࢖ͬͯૹ৴ .BSLEPXO ύʔαʔ EBJGVLV τϥϯεύΠϥ ఆٛΛ ࢀর 04ϩάΛऔಘ தؒදݱΛ 4XJGU ίʔυԽ ʢ։ൃ൛ΞϓϦͷΈʣ
  20. ΞϓϦͷϩά࣮૷ͷؔ࿈ਤ ϩάఆٛ .BSLEPXO 04-PH 04-PH4UPSF ΞϓϦ಺ ϩά֬ೝπʔϧ ϩάఆٛ 4XJGU ϩάૹ৴ϥΠϒϥϦ

    PT-PHHFS ϩΨʔ 04ϩάʹ΋ग़ྗ ϩάαʔόʔ΁ૹ৴ ఆٛΛ࢖ͬͯૹ৴ .BSLEPXO ύʔαʔ EBJGVLV τϥϯεύΠϥ ఆٛΛ ࢀর 04ϩάΛऔಘ தؒදݱΛ 4XJGU ίʔυԽ ʢ։ൃ൛ΞϓϦͷΈʣ
  21. 04-PH4UPSF ར༻ྫ J04 import OSLog …… let store = try

    OSLogStore(scope: .currentProcessIdentifier) let predicate = NSPredicate(format: "(subsystem == %@)", Bundle.main.bundleIdentifier!) return try store.getEntries(matching: predicate)
  22. ΞϓϦͷϩά࣮૷ͷؔ࿈ਤ ϩάఆٛ .BSLEPXO 04-PH 04-PH4UPSF ΞϓϦ಺ ϩά֬ೝπʔϧ ϩάఆٛ 4XJGU ϩάૹ৴ϥΠϒϥϦ

    PT-PHHFS ϩΨʔ 04ϩάʹ΋ग़ྗ ϩάαʔόʔ΁ૹ৴ ఆٛΛ࢖ͬͯૹ৴ .BSLEPXO ύʔαʔ EBJGVLV τϥϯεύΠϥ ఆٛΛ ࢀর 04ϩάΛऔಘ தؒදݱΛ 4XJGU ίʔυԽ ʢ։ൃ൛ΞϓϦͷΈʣ
  23. ΞϓϦ಺ϩά֬ೝπʔϧͷߏ੒ 04-PH4UPSF ΞϓϦ಺ϩά֬ೝπʔϧ HFU&OUSJFT [OSLogEntry] [OSLogEntryLog] ߦಈϩά ఆٛ ߦಈϩάఆٛ .BSLEPXO

    ϩά֬ೝπʔϧ༻ͷϞσϧ ߦಈϩάͷ+40/Λσίʔυ DPNQBDU.BQ [OSLogMessageComponent] ʹؚ·ΕΔ
  24. ΞϓϦͷϩά࣮૷ͷؔ࿈ਤ ϩάఆٛ .BSLEPXO 04-PH 04-PH4UPSF ΞϓϦ಺ ϩά֬ೝπʔϧ ϩάఆٛ 4XJGU ϩάૹ৴ϥΠϒϥϦ

    PT-PHHFS ϩΨʔ 04ϩάʹ΋ग़ྗ ϩάαʔόʔ΁ૹ৴ ఆٛΛ࢖ͬͯૹ৴ .BSLEPXO ύʔαʔ EBJGVLV τϥϯεύΠϥ ఆٛΛ ࢀর 04ϩάΛऔಘ தؒදݱΛ 4XJGU ίʔυԽ ʢ։ൃ൛ΞϓϦͷΈʣ
  25. DPPLQBE@JPTED@BGUFS@QBSUZ w $BTF1BUIT w .BJOUBJOBCJMJUZ*OEFYͱ ίʔυͷอकੑվળ w %PD$%PDVNFOUBUJPO "SDIJWF w

    0QFO"1*  ౳ͷτϐοΫͰ࿩͠·͢ʂ IUUQTDPPLQBEDPOOQBTTDPNFWFOU