From bb9567f1c4aed52e7623d053e335c44c9526439c Mon Sep 17 00:00:00 2001 From: Goban Date: Tue, 3 Oct 2023 14:28:16 +0900 Subject: [PATCH 01/10] =?UTF-8?q?[feat]=20=EB=A1=9C=EA=B9=85=201=EC=B0=A8?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dependency+Target.swift | 5 ++ Projects/App/Sources/DI/DomainAssembly.swift | 5 +- Projects/App/Sources/LitoApp.swift | 9 ++- Projects/Domain/Project.swift | 1 + .../Sources/Logging/OrderClickedScheme.swift | 54 +++++++++++++++ .../UseCase/SovingProblemUseCase.swift | 18 ++++- .../SolvingProblemListViewModel.swift | 6 ++ Projects/SWMLogging/Project.swift | 19 ++++++ Projects/SWMLogging/Sources/API.swift | 38 +++++++++++ Projects/SWMLogging/Sources/Logger.swift | 68 +++++++++++++++++++ .../SWMLogging/Tests/SWMLoggingTests.swift | 2 + 11 files changed, 222 insertions(+), 3 deletions(-) create mode 100644 Projects/Domain/Sources/Logging/OrderClickedScheme.swift create mode 100644 Projects/SWMLogging/Project.swift create mode 100644 Projects/SWMLogging/Sources/API.swift create mode 100644 Projects/SWMLogging/Sources/Logger.swift create mode 100644 Projects/SWMLogging/Tests/SWMLoggingTests.swift diff --git a/Plugins/DependencyPlugin/ProjectDescriptionHelpers/Dependency+Target.swift b/Plugins/DependencyPlugin/ProjectDescriptionHelpers/Dependency+Target.swift index 5d72f146..961d6302 100644 --- a/Plugins/DependencyPlugin/ProjectDescriptionHelpers/Dependency+Target.swift +++ b/Plugins/DependencyPlugin/ProjectDescriptionHelpers/Dependency+Target.swift @@ -17,4 +17,9 @@ public extension TargetDependency.Projcet { target: "Data", path: .relativeToRoot("Projects/Data") ) + + static let SWMLogging = TargetDependency.project( + target: "SWMLogging", + path: .relativeToRoot("Projects/SWMLogging") + ) } diff --git a/Projects/App/Sources/DI/DomainAssembly.swift b/Projects/App/Sources/DI/DomainAssembly.swift index e58cfd05..f08b700a 100644 --- a/Projects/App/Sources/DI/DomainAssembly.swift +++ b/Projects/App/Sources/DI/DomainAssembly.swift @@ -8,9 +8,12 @@ import Domain import Swinject +import SWMLogging public struct DomainAssembly: Assembly { + let logger: SWMLogger + public func assemble(container: Container) { // ------------------------ Common ------------------------ container.register(ExampleUseCase.self) { resolver in @@ -46,7 +49,7 @@ public struct DomainAssembly: Assembly { } container.register(SolvingProblemListUseCase.self) { resolver in let repository = resolver.resolve(ProblemRepository.self)! - return DefaultSolvingProblemListUseCase(repository: repository) + return DefaultSolvingProblemListUseCase(repository: repository, logger: logger) } container.register(FavoriteProblemListUseCase.self) { resolver in let repository = resolver.resolve(ProblemRepository.self)! diff --git a/Projects/App/Sources/LitoApp.swift b/Projects/App/Sources/LitoApp.swift index 549ecc71..23dc9496 100644 --- a/Projects/App/Sources/LitoApp.swift +++ b/Projects/App/Sources/LitoApp.swift @@ -4,22 +4,29 @@ import Presentation import Domain import Swinject import KakaoSDKCommon +import SWMLogging @main struct LitoApp: App { private let injector: Injector @ObservedObject private var coordinator: Coordinator @ObservedObject private var toastHelper: ToastHelper + private let logger: SWMLogger init() { UIFont.registerCommonFonts() let kakaoAppKey = Bundle.main.infoDictionary?["KAKAO_NATIVE_APP_KEY"] ?? "" + // Logging 객체 생성 + // Logging.init(mandatory 요소) KakaoSDK.initSDK(appKey: kakaoAppKey as! String) injector = DependencyInjector(container: Container()) toastHelper = ToastHelper() coordinator = Coordinator(.loginScene) - injector.assemble([DomainAssembly(), + // OS NameAndVersion 기기에서 불러오기 + logger = SWMLogger(serverUrl: "https://dev.swm-lgtm.com", serverPath: "/v1/log", OSNameAndVersion: "iOS 16") + // domainAssembly 에 Logging 객체 주입 + injector.assemble([DomainAssembly(logger: logger), DataAssembly(), PresentationAssembly( coordinator: coordinator, diff --git a/Projects/Domain/Project.swift b/Projects/Domain/Project.swift index 5ec1e88d..17abe016 100644 --- a/Projects/Domain/Project.swift +++ b/Projects/Domain/Project.swift @@ -14,5 +14,6 @@ let project = Project.makeModule( platform: .iOS, product: .staticFramework, dependencies: [ + .Projcet.SWMLogging ] ) diff --git a/Projects/Domain/Sources/Logging/OrderClickedScheme.swift b/Projects/Domain/Sources/Logging/OrderClickedScheme.swift new file mode 100644 index 00000000..399572d5 --- /dev/null +++ b/Projects/Domain/Sources/Logging/OrderClickedScheme.swift @@ -0,0 +1,54 @@ +// +// OrderClickedScheme.swift +// Domain +// +// Created by Lee Myeonghwan on 2023/10/02. +// Copyright © 2023 com.lito. All rights reserved. +// + +import Foundation +import SWMLogging + +public struct OrderClickedScheme: ClickScheme { + + public var eventLogName = "missionClick" + public var screenName = "SolvingProblemListView" + public var logVersion = 1 + public var logData: [String: String] = [:] + + public init(userId: Int?, gender: String?, age: Int?) { + + //logData 만들기 + self.logData["userId"] = String(userId ?? -1) + self.logData["gender"] = gender + self.logData["age"] = String(age ?? -1) + + } + + public class Builder: SWMSchemeBuilder { + let userId: Int? + var gender: String? + var age: Int? + + public init(userId: Int? = nil, gender: String? = nil, age: Int? = nil) { + self.userId = userId + self.gender = gender + self.age = age + } + + public func setGender(gender: String) -> Builder { + self.gender = gender + return self + } + public func setAge(age: Int) -> Builder { + self.age = age + return self + } + + public func build() -> SWMLoggingScheme { + return OrderClickedScheme(userId: userId, gender: gender, age: age) + } + + } + +} diff --git a/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift b/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift index 3dc36556..3bf0dd2f 100644 --- a/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift +++ b/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift @@ -8,17 +8,27 @@ import Combine import Foundation +import SWMLogging public protocol SolvingProblemListUseCase { func toggleProblemFavorite(id: Int) -> AnyPublisher func getProblemList(problemsQueryDTO: SolvingProblemsQueryDTO) -> AnyPublisher + func fireLogging(scheme: SWMLoggingScheme) } public final class DefaultSolvingProblemListUseCase: SolvingProblemListUseCase { +// let logging = SWMLogging + public func fireLogging(scheme: SWMLogging.SWMLoggingScheme) { +// let builder = OrderClickedBuilder + logger.fireLogging(scheme, authorization: "eyJhbGciOiJIUzI1NiJ9.eyJnaXRodWJJZCI6Ikt4eEh5b1JpbSIsImlhdCI6MTY5NTcxNDE1MiwiZXhwIjoxNzI3MjUwMTUyfQ.tbQFKNIQCekhWZjHwOqQNBIY3YgXZZm-B95NyTvBn5c") + } + private let repository: ProblemRepository + private let logger: SWMLogger - public init(repository: ProblemRepository) { + public init(repository: ProblemRepository, logger: SWMLogger) { self.repository = repository + self.logger = logger } public func toggleProblemFavorite(id: Int) -> AnyPublisher { @@ -28,4 +38,10 @@ public final class DefaultSolvingProblemListUseCase: SolvingProblemListUseCase { public func getProblemList(problemsQueryDTO: SolvingProblemsQueryDTO) -> AnyPublisher { repository.getProblemList(problemsQueryDTO: problemsQueryDTO) } + + // protocol scheme: encodable + // click, exposure 의 상위 추상화 객체 +// public func fireLogging(scheme: Scheme) { +// SWMLogging.fireLogging(scheme: <#T##Scheme#>) +// } } diff --git a/Projects/Presentation/Sources/Views/SolvingProblemList/SolvingProblemListViewModel.swift b/Projects/Presentation/Sources/Views/SolvingProblemList/SolvingProblemListViewModel.swift index e0a282ae..a4339f34 100644 --- a/Projects/Presentation/Sources/Views/SolvingProblemList/SolvingProblemListViewModel.swift +++ b/Projects/Presentation/Sources/Views/SolvingProblemList/SolvingProblemListViewModel.swift @@ -40,6 +40,12 @@ public final class SolvingProblemListViewModel: BaseViewModel { // 화면이 다시 떴을 때 혹시나 바뀌었을 값들을 위해 마지막으로 본 문제까지 전부 업데이트해주기 public func onScreenAppeared() { + + let orderClickedScheme = OrderClickedScheme.Builder() + .setAge(age: 0) + .setGender(gender: "man") + .build() + useCase.fireLogging(scheme: orderClickedScheme) lastNetworkAction = onScreenAppeared if problemCellList.isEmpty { return diff --git a/Projects/SWMLogging/Project.swift b/Projects/SWMLogging/Project.swift new file mode 100644 index 00000000..879b48c5 --- /dev/null +++ b/Projects/SWMLogging/Project.swift @@ -0,0 +1,19 @@ +// +// Project.swift +// ProjectDescriptionHelpers +// +// Created by Lee Myeonghwan on 2023/10/02. +// + +import ProjectDescription +import ProjectDescriptionHelpers +import DependencyPlugin + +let project = Project.makeModule( + name: "SWMLogging", + product: .staticLibrary, + dependencies: [ + .SPM.Moya, + .SPM.CombineMoya + ] +) diff --git a/Projects/SWMLogging/Sources/API.swift b/Projects/SWMLogging/Sources/API.swift new file mode 100644 index 00000000..00d73439 --- /dev/null +++ b/Projects/SWMLogging/Sources/API.swift @@ -0,0 +1,38 @@ +// +// API.swift +// SWMLogging +// +// Created by Lee Myeonghwan on 2023/10/02. +// Copyright © 2023 com.lito. All rights reserved. +// + +import Foundation +import Moya + +struct LoggingAPI: TargetType { + let serverUrl: String + let serverPath: String + let authorization: String + let scheme: SWMLoggingScheme + + var baseURL: URL { + return URL(string: serverUrl)! + } + + var path: String { + return serverPath + } + + var method: Moya.Method { + return .post + } + + var task: Moya.Task { + return .requestJSONEncodable(scheme) + } + + var headers: [String: String]? { + return ["Content-Type": "application/json", "Authorization": "Bearer \(authorization)"] + } + +} diff --git a/Projects/SWMLogging/Sources/Logger.swift b/Projects/SWMLogging/Sources/Logger.swift new file mode 100644 index 00000000..fdb00ea6 --- /dev/null +++ b/Projects/SWMLogging/Sources/Logger.swift @@ -0,0 +1,68 @@ +// +// Source.swift +// ProjectDescriptionHelpers +// +// Created by Lee Myeonghwan on 2023/10/02. +// + +import Foundation +import Combine +import Moya +import CombineMoya + +public protocol SWMLoggingScheme: Encodable { + var eventLogName: String { get set} + var screenName: String { get set } + var logVersion: Int { get set } + var logData: [String: String] {get set } +} + +// protocol scheme: encodable +// click, exposure 의 상위 추상화 객체 + +public protocol ClickScheme: SWMLoggingScheme { + // Business Static Paramter +} + +public protocol ExposureScheme: SWMLoggingScheme { + // Business Static Paramter +} + +public protocol SWMSchemeBuilder { + func build() -> SWMLoggingScheme +} + +public class SWMLogger { + + private let serverUrl: String + private let serverPath: String + private let OSNameAndVersion: String + private let moyaProvider = MoyaProvider() + private var cancelBag = Set() + + public init(serverUrl: String, serverPath: String, OSNameAndVersion: String) { + self.serverUrl = serverUrl + self.serverPath = serverPath + self.OSNameAndVersion = OSNameAndVersion + } + + public func fireLogging(_ scheme: SWMLoggingScheme, authorization: String) { + + let loggingAPI = LoggingAPI( + serverUrl: serverUrl, + serverPath: serverPath, + authorization: authorization, + scheme: scheme) + moyaProvider.requestPublisher(loggingAPI) + .sink(receiveCompletion: { result in + switch result { + case let .failure(error): + print(error) + default: break + } + }, receiveValue: { _ in + print("suceess") + }) + .store(in: &cancelBag) + } +} diff --git a/Projects/SWMLogging/Tests/SWMLoggingTests.swift b/Projects/SWMLogging/Tests/SWMLoggingTests.swift new file mode 100644 index 00000000..350c82fa --- /dev/null +++ b/Projects/SWMLogging/Tests/SWMLoggingTests.swift @@ -0,0 +1,2 @@ + +import Foundation From 8b879b47ba573424b17bb2252cd74f8fb05b9c9a Mon Sep 17 00:00:00 2001 From: Goban Date: Tue, 3 Oct 2023 16:29:26 +0900 Subject: [PATCH 02/10] =?UTF-8?q?[refactor]=20=EB=A1=9C=EA=B9=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/App/Sources/LitoApp.swift | 3 +- .../Sources/Logging/OrderClickedScheme.swift | 2 +- .../UseCase/SovingProblemUseCase.swift | 10 +---- Projects/SWMLogging/Sources/API.swift | 17 +++++-- Projects/SWMLogging/Sources/Logger.swift | 44 ++++++++++--------- 5 files changed, 39 insertions(+), 37 deletions(-) diff --git a/Projects/App/Sources/LitoApp.swift b/Projects/App/Sources/LitoApp.swift index 23dc9496..6f431a4b 100644 --- a/Projects/App/Sources/LitoApp.swift +++ b/Projects/App/Sources/LitoApp.swift @@ -11,7 +11,6 @@ struct LitoApp: App { private let injector: Injector @ObservedObject private var coordinator: Coordinator @ObservedObject private var toastHelper: ToastHelper - private let logger: SWMLogger init() { UIFont.registerCommonFonts() @@ -24,7 +23,7 @@ struct LitoApp: App { toastHelper = ToastHelper() coordinator = Coordinator(.loginScene) // OS NameAndVersion 기기에서 불러오기 - logger = SWMLogger(serverUrl: "https://dev.swm-lgtm.com", serverPath: "/v1/log", OSNameAndVersion: "iOS 16") + let logger = SWMLogger(serverUrl: "https://dev.swm-lgtm.com", serverPath: "/v1/log", OSNameAndVersion: "iOS 16", appVersion: "1.0") // domainAssembly 에 Logging 객체 주입 injector.assemble([DomainAssembly(logger: logger), DataAssembly(), diff --git a/Projects/Domain/Sources/Logging/OrderClickedScheme.swift b/Projects/Domain/Sources/Logging/OrderClickedScheme.swift index 399572d5..cc562838 100644 --- a/Projects/Domain/Sources/Logging/OrderClickedScheme.swift +++ b/Projects/Domain/Sources/Logging/OrderClickedScheme.swift @@ -25,7 +25,7 @@ public struct OrderClickedScheme: ClickScheme { } - public class Builder: SWMSchemeBuilder { + public class Builder { let userId: Int? var gender: String? var age: Int? diff --git a/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift b/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift index 3bf0dd2f..65e795b1 100644 --- a/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift +++ b/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift @@ -17,10 +17,8 @@ public protocol SolvingProblemListUseCase { } public final class DefaultSolvingProblemListUseCase: SolvingProblemListUseCase { -// let logging = SWMLogging public func fireLogging(scheme: SWMLogging.SWMLoggingScheme) { -// let builder = OrderClickedBuilder - logger.fireLogging(scheme, authorization: "eyJhbGciOiJIUzI1NiJ9.eyJnaXRodWJJZCI6Ikt4eEh5b1JpbSIsImlhdCI6MTY5NTcxNDE1MiwiZXhwIjoxNzI3MjUwMTUyfQ.tbQFKNIQCekhWZjHwOqQNBIY3YgXZZm-B95NyTvBn5c") + logger.shotLogging(scheme, authorization: "eyJhbGciOiJIUzI1NiJ9.eyJnaXRodWJJZCI6Ikt4eEh5b1JpbSIsImlhdCI6MTY5NTcxNDE1MiwiZXhwIjoxNzI3MjUwMTUyfQ.tbQFKNIQCekhWZjHwOqQNBIY3YgXZZm-B95NyTvBn5c") } private let repository: ProblemRepository @@ -38,10 +36,4 @@ public final class DefaultSolvingProblemListUseCase: SolvingProblemListUseCase { public func getProblemList(problemsQueryDTO: SolvingProblemsQueryDTO) -> AnyPublisher { repository.getProblemList(problemsQueryDTO: problemsQueryDTO) } - - // protocol scheme: encodable - // click, exposure 의 상위 추상화 객체 -// public func fireLogging(scheme: Scheme) { -// SWMLogging.fireLogging(scheme: <#T##Scheme#>) -// } } diff --git a/Projects/SWMLogging/Sources/API.swift b/Projects/SWMLogging/Sources/API.swift index 00d73439..8fc2ef31 100644 --- a/Projects/SWMLogging/Sources/API.swift +++ b/Projects/SWMLogging/Sources/API.swift @@ -12,8 +12,17 @@ import Moya struct LoggingAPI: TargetType { let serverUrl: String let serverPath: String - let authorization: String - let scheme: SWMLoggingScheme + let authorization: String? = nil + var schemeData: Data = Data() + + public init(serverUrl: String, serverPath: String) { + self.serverUrl = serverUrl + self.serverPath = serverPath + } + + public mutating func setScheme(_ schemeData: Data) { + self.schemeData = schemeData + } var baseURL: URL { return URL(string: serverUrl)! @@ -28,11 +37,11 @@ struct LoggingAPI: TargetType { } var task: Moya.Task { - return .requestJSONEncodable(scheme) + return .requestData(schemeData) } var headers: [String: String]? { - return ["Content-Type": "application/json", "Authorization": "Bearer \(authorization)"] + return ["Content-Type": "application/json", "Authorization": "Bearer \(authorization ?? "")"] } } diff --git a/Projects/SWMLogging/Sources/Logger.swift b/Projects/SWMLogging/Sources/Logger.swift index fdb00ea6..e50a42c9 100644 --- a/Projects/SWMLogging/Sources/Logger.swift +++ b/Projects/SWMLogging/Sources/Logger.swift @@ -11,14 +11,17 @@ import Moya import CombineMoya public protocol SWMLoggingScheme: Encodable { - var eventLogName: String { get set} + var eventLogName: String { get set } var screenName: String { get set } var logVersion: Int { get set } - var logData: [String: String] {get set } + var logData: [String: String] { get set } } -// protocol scheme: encodable -// click, exposure 의 상위 추상화 객체 +extension SWMLoggingScheme { + func makeJson() throws -> Data { + return try SWMLogger.encoder.encode(self) + } +} public protocol ClickScheme: SWMLoggingScheme { // Business Static Paramter @@ -28,31 +31,26 @@ public protocol ExposureScheme: SWMLoggingScheme { // Business Static Paramter } -public protocol SWMSchemeBuilder { - func build() -> SWMLoggingScheme -} - public class SWMLogger { - private let serverUrl: String - private let serverPath: String - private let OSNameAndVersion: String + static let encoder = JSONEncoder() private let moyaProvider = MoyaProvider() + + private let sessionId = UUID() + private let appVersion: String + private let OSNameAndVersion: String private var cancelBag = Set() + private var loggingAPI: LoggingAPI - public init(serverUrl: String, serverPath: String, OSNameAndVersion: String) { - self.serverUrl = serverUrl - self.serverPath = serverPath + public init(serverUrl: String, serverPath: String, OSNameAndVersion: String, appVersion: String) { self.OSNameAndVersion = OSNameAndVersion + self.appVersion = appVersion + loggingAPI = LoggingAPI(serverUrl: serverUrl, serverPath: serverPath) } - public func fireLogging(_ scheme: SWMLoggingScheme, authorization: String) { - - let loggingAPI = LoggingAPI( - serverUrl: serverUrl, - serverPath: serverPath, - authorization: authorization, - scheme: scheme) + public func shotLogging(_ scheme: SWMLoggingScheme, authorization: String) { + do { + loggingAPI.setScheme(try scheme.makeJson()) moyaProvider.requestPublisher(loggingAPI) .sink(receiveCompletion: { result in switch result { @@ -64,5 +62,9 @@ public class SWMLogger { print("suceess") }) .store(in: &cancelBag) + } catch { + + } + } } From 113d87c0ff91fdff8c4935f85692695bd43d3f7a Mon Sep 17 00:00:00 2001 From: Goban Date: Wed, 4 Oct 2023 13:46:19 +0900 Subject: [PATCH 03/10] =?UTF-8?q?[chore]=20shotLogging=20throw=20=EB=A1=9C?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/Domain/Sources/Logging/OrderClickedScheme.swift | 2 +- Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift | 6 +++++- Projects/SWMLogging/Sources/Logger.swift | 5 +++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Projects/Domain/Sources/Logging/OrderClickedScheme.swift b/Projects/Domain/Sources/Logging/OrderClickedScheme.swift index cc562838..27d735a3 100644 --- a/Projects/Domain/Sources/Logging/OrderClickedScheme.swift +++ b/Projects/Domain/Sources/Logging/OrderClickedScheme.swift @@ -18,7 +18,7 @@ public struct OrderClickedScheme: ClickScheme { public init(userId: Int?, gender: String?, age: Int?) { - //logData 만들기 + // logData 만들기 self.logData["userId"] = String(userId ?? -1) self.logData["gender"] = gender self.logData["age"] = String(age ?? -1) diff --git a/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift b/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift index 65e795b1..9ce2852c 100644 --- a/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift +++ b/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift @@ -18,7 +18,11 @@ public protocol SolvingProblemListUseCase { public final class DefaultSolvingProblemListUseCase: SolvingProblemListUseCase { public func fireLogging(scheme: SWMLogging.SWMLoggingScheme) { - logger.shotLogging(scheme, authorization: "eyJhbGciOiJIUzI1NiJ9.eyJnaXRodWJJZCI6Ikt4eEh5b1JpbSIsImlhdCI6MTY5NTcxNDE1MiwiZXhwIjoxNzI3MjUwMTUyfQ.tbQFKNIQCekhWZjHwOqQNBIY3YgXZZm-B95NyTvBn5c") + do { + try logger.shotLogging(scheme, authorization: "eyJhbGciOiJIUzI1NiJ9.eyJnaXRodWJJZCI6Ikt4eEh5b1JpbSIsImlhdCI6MTY5NTcxNDE1MiwiZXhwIjoxNzI3MjUwMTUyfQ.tbQFKNIQCekhWZjHwOqQNBIY3YgXZZm-B95NyTvBn5c") + } catch { + + } } private let repository: ProblemRepository diff --git a/Projects/SWMLogging/Sources/Logger.swift b/Projects/SWMLogging/Sources/Logger.swift index e50a42c9..0fe9a0b0 100644 --- a/Projects/SWMLogging/Sources/Logger.swift +++ b/Projects/SWMLogging/Sources/Logger.swift @@ -48,7 +48,8 @@ public class SWMLogger { loggingAPI = LoggingAPI(serverUrl: serverUrl, serverPath: serverPath) } - public func shotLogging(_ scheme: SWMLoggingScheme, authorization: String) { + // throw + public func shotLogging(_ scheme: SWMLoggingScheme, authorization: String) throws { do { loggingAPI.setScheme(try scheme.makeJson()) moyaProvider.requestPublisher(loggingAPI) @@ -63,7 +64,7 @@ public class SWMLogger { }) .store(in: &cancelBag) } catch { - + throw error } } From c056f0f02b961e1277fc7e7949fde0c438b080f7 Mon Sep 17 00:00:00 2001 From: Goban Date: Wed, 4 Oct 2023 13:49:32 +0900 Subject: [PATCH 04/10] =?UTF-8?q?[chore]=20=EB=B9=A0=EC=A7=84=20userId=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/Domain/Sources/Logging/OrderClickedScheme.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Projects/Domain/Sources/Logging/OrderClickedScheme.swift b/Projects/Domain/Sources/Logging/OrderClickedScheme.swift index 27d735a3..0103410f 100644 --- a/Projects/Domain/Sources/Logging/OrderClickedScheme.swift +++ b/Projects/Domain/Sources/Logging/OrderClickedScheme.swift @@ -26,7 +26,7 @@ public struct OrderClickedScheme: ClickScheme { } public class Builder { - let userId: Int? + var userId: Int? var gender: String? var age: Int? @@ -44,6 +44,11 @@ public struct OrderClickedScheme: ClickScheme { self.age = age return self } + + public func userId(id: Int) -> Builder { + self.userId = id + return self + } public func build() -> SWMLoggingScheme { return OrderClickedScheme(userId: userId, gender: gender, age: age) From 6c2cd6e34a77550226018cb1a555d7cc752ee9ab Mon Sep 17 00:00:00 2001 From: Goban Date: Thu, 5 Oct 2023 13:15:33 +0900 Subject: [PATCH 05/10] =?UTF-8?q?[feat]=20observer=20=EC=9E=91=EC=97=85?= =?UTF-8?q?=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../App/Sources/DI/PresentationAssembly.swift | 4 +++- Projects/App/Sources/LitoApp.swift | 3 ++- .../UseCase/SovingProblemUseCase.swift | 2 ++ .../SolvingProblemListViewModel.swift | 10 ++++++++- Projects/SWMLogging/Sources/Logger.swift | 21 ++++++++++++++++++- 5 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Projects/App/Sources/DI/PresentationAssembly.swift b/Projects/App/Sources/DI/PresentationAssembly.swift index f3ab3490..1763dfef 100644 --- a/Projects/App/Sources/DI/PresentationAssembly.swift +++ b/Projects/App/Sources/DI/PresentationAssembly.swift @@ -9,11 +9,13 @@ import Swinject import Domain import Presentation +import SWMLogging public struct PresentationAssembly: Assembly { let coordinator: Coordinator let toastHelper: ToastHelper + let logger: SWMLogger public func assemble(container: Container) { // ------------------------ Common ------------------------ @@ -79,7 +81,7 @@ public struct PresentationAssembly: Assembly { // SolvingProblemList container.register(SolvingProblemListViewModel.self) { resolver in let useCase = resolver.resolve(SolvingProblemListUseCase.self)! - return SolvingProblemListViewModel(useCase: useCase, coordinator: coordinator, toastHelper: toastHelper) + return SolvingProblemListViewModel(useCase: useCase, coordinator: coordinator, toastHelper: toastHelper, logger: logger) } container.register(SolvingProblemListView.self) { resolver in diff --git a/Projects/App/Sources/LitoApp.swift b/Projects/App/Sources/LitoApp.swift index 6f431a4b..d1f317fb 100644 --- a/Projects/App/Sources/LitoApp.swift +++ b/Projects/App/Sources/LitoApp.swift @@ -29,7 +29,8 @@ struct LitoApp: App { DataAssembly(), PresentationAssembly( coordinator: coordinator, - toastHelper: toastHelper + toastHelper: toastHelper, + logger: logger )]) coordinator.injector = injector if KeyChainManager.isPossibleAutoLogin { diff --git a/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift b/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift index 9ce2852c..3d133eda 100644 --- a/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift +++ b/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift @@ -19,6 +19,8 @@ public protocol SolvingProblemListUseCase { public final class DefaultSolvingProblemListUseCase: SolvingProblemListUseCase { public func fireLogging(scheme: SWMLogging.SWMLoggingScheme) { do { +// logger.hotObservable.onNext(scheme) + try logger.shotLogging(scheme, authorization: "eyJhbGciOiJIUzI1NiJ9.eyJnaXRodWJJZCI6Ikt4eEh5b1JpbSIsImlhdCI6MTY5NTcxNDE1MiwiZXhwIjoxNzI3MjUwMTUyfQ.tbQFKNIQCekhWZjHwOqQNBIY3YgXZZm-B95NyTvBn5c") try logger.shotLogging(scheme, authorization: "eyJhbGciOiJIUzI1NiJ9.eyJnaXRodWJJZCI6Ikt4eEh5b1JpbSIsImlhdCI6MTY5NTcxNDE1MiwiZXhwIjoxNzI3MjUwMTUyfQ.tbQFKNIQCekhWZjHwOqQNBIY3YgXZZm-B95NyTvBn5c") } catch { diff --git a/Projects/Presentation/Sources/Views/SolvingProblemList/SolvingProblemListViewModel.swift b/Projects/Presentation/Sources/Views/SolvingProblemList/SolvingProblemListViewModel.swift index 20ac4214..91318ef5 100644 --- a/Projects/Presentation/Sources/Views/SolvingProblemList/SolvingProblemListViewModel.swift +++ b/Projects/Presentation/Sources/Views/SolvingProblemList/SolvingProblemListViewModel.swift @@ -9,6 +9,7 @@ import SwiftUI import Domain import Combine +import SWMLogging public final class SolvingProblemListViewModel: BaseViewModel { private let useCase: SolvingProblemListUseCase @@ -17,9 +18,11 @@ public final class SolvingProblemListViewModel: BaseViewModel { private var problemTotalSize: Int? @Published private(set) var isLoading: Bool = false @Published var problemCellList: [SolvingProblemCellVO] = [] + private let logger: SWMLogger - public init(useCase: SolvingProblemListUseCase, coordinator: CoordinatorProtocol, toastHelper: ToastHelperProtocol) { + public init(useCase: SolvingProblemListUseCase, coordinator: CoordinatorProtocol, toastHelper: ToastHelperProtocol, logger: SWMLogger) { self.useCase = useCase + self.logger = logger super.init(coordinator: coordinator, toastHelper: toastHelper) } @@ -108,5 +111,10 @@ extension SolvingProblemListViewModel: ProblemCellHandling { self.problemCellList[index].favorite.toggle() }, errorHandler: errorHandler) .store(in: cancelBag) + let clickScheme = OrderClickedScheme.Builder() + .setAge(age: 0) + .setGender(gender: "0") + .build() + useCase.fireLogging(scheme: clickScheme) } } diff --git a/Projects/SWMLogging/Sources/Logger.swift b/Projects/SWMLogging/Sources/Logger.swift index 0fe9a0b0..d95196eb 100644 --- a/Projects/SWMLogging/Sources/Logger.swift +++ b/Projects/SWMLogging/Sources/Logger.swift @@ -9,8 +9,9 @@ import Foundation import Combine import Moya import CombineMoya +import RxSwift -public protocol SWMLoggingScheme: Encodable { +public protocol SWMLoggingScheme: Encodable{ var eventLogName: String { get set } var screenName: String { get set } var logVersion: Int { get set } @@ -41,16 +42,34 @@ public class SWMLogger { private let OSNameAndVersion: String private var cancelBag = Set() private var loggingAPI: LoggingAPI + let disposeBag = DisposeBag() + public let hotObservable = PublishSubject() + private var latestLogName = "" public init(serverUrl: String, serverPath: String, OSNameAndVersion: String, appVersion: String) { self.OSNameAndVersion = OSNameAndVersion self.appVersion = appVersion loggingAPI = LoggingAPI(serverUrl: serverUrl, serverPath: serverPath) + hotObservable +// .flatMap({ scheme -> Observable in +// if scheme.eventLogName == latestLogName { +// return Observable +// // .throttle(for: , scheduler: <#T##Scheduler#>, latest: <#T##Bool#>) +// } else { +// return Just(scheme) +// } +// }) + .subscribe(onNext: { scheme in + print("scheme", scheme) + self.latestLogName = scheme.eventLogName + }) + .disposed(by: disposeBag) } // throw public func shotLogging(_ scheme: SWMLoggingScheme, authorization: String) throws { do { + hotObservable.onNext(scheme) loggingAPI.setScheme(try scheme.makeJson()) moyaProvider.requestPublisher(loggingAPI) .sink(receiveCompletion: { result in From 160969b32445b9c18899f19a70c708a85af6ddee Mon Sep 17 00:00:00 2001 From: ddophi98 Date: Mon, 9 Oct 2023 13:11:47 +0900 Subject: [PATCH 06/10] =?UTF-8?q?[feat]=20throttle=20=EC=8B=9C=EB=8F=84=20?= =?UTF-8?q?1=EC=B0=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/SWMLogging/Sources/Logger.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Projects/SWMLogging/Sources/Logger.swift b/Projects/SWMLogging/Sources/Logger.swift index d95196eb..91cb9414 100644 --- a/Projects/SWMLogging/Sources/Logger.swift +++ b/Projects/SWMLogging/Sources/Logger.swift @@ -52,11 +52,11 @@ public class SWMLogger { loggingAPI = LoggingAPI(serverUrl: serverUrl, serverPath: serverPath) hotObservable // .flatMap({ scheme -> Observable in -// if scheme.eventLogName == latestLogName { -// return Observable -// // .throttle(for: , scheduler: <#T##Scheduler#>, latest: <#T##Bool#>) +// if scheme.eventLogName == self.latestLogName { +// return self.hotObservable +// .throttle(.seconds(1), scheduler: MainScheduler.instance) // } else { -// return Just(scheme) +// return Observable.just(scheme) // } // }) .subscribe(onNext: { scheme in From 5d9b1bf24381bb959ed5608f3d296d151b90a7d8 Mon Sep 17 00:00:00 2001 From: ddophi98 Date: Mon, 9 Oct 2023 13:45:59 +0900 Subject: [PATCH 07/10] =?UTF-8?q?[feat]=20AnyEncodable=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EC=BB=A4=EC=8A=A4=ED=85=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Logging/OrderClickedScheme.swift | 8 +++---- .../SWMLogging/Sources/AnyEncodable.swift | 24 +++++++++++++++++++ Projects/SWMLogging/Sources/Logger.swift | 4 ++-- 3 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 Projects/SWMLogging/Sources/AnyEncodable.swift diff --git a/Projects/Domain/Sources/Logging/OrderClickedScheme.swift b/Projects/Domain/Sources/Logging/OrderClickedScheme.swift index 0103410f..e598a60e 100644 --- a/Projects/Domain/Sources/Logging/OrderClickedScheme.swift +++ b/Projects/Domain/Sources/Logging/OrderClickedScheme.swift @@ -14,14 +14,14 @@ public struct OrderClickedScheme: ClickScheme { public var eventLogName = "missionClick" public var screenName = "SolvingProblemListView" public var logVersion = 1 - public var logData: [String: String] = [:] + public var logData: [String: AnyEncodable] = [:] public init(userId: Int?, gender: String?, age: Int?) { // logData 만들기 - self.logData["userId"] = String(userId ?? -1) - self.logData["gender"] = gender - self.logData["age"] = String(age ?? -1) + self.logData["userId"] = .int(userId ?? -1) + self.logData["gender"] = .string(gender ?? "") + self.logData["age"] = .int(age ?? -1) } diff --git a/Projects/SWMLogging/Sources/AnyEncodable.swift b/Projects/SWMLogging/Sources/AnyEncodable.swift new file mode 100644 index 00000000..f1efffa0 --- /dev/null +++ b/Projects/SWMLogging/Sources/AnyEncodable.swift @@ -0,0 +1,24 @@ +// +// AnyEncodable.swift +// SWMLogging +// +// Created by 김동락 on 2023/10/09. +// Copyright © 2023 com.lito. All rights reserved. +// + +import Foundation + +// 필요한 encodable 타입 추가 가능 +public enum AnyEncodable: Encodable { + case int(Int), string(String) + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .int(let value): + try container.encode(value) + case .string(let value): + try container.encode(value) + } + } +} diff --git a/Projects/SWMLogging/Sources/Logger.swift b/Projects/SWMLogging/Sources/Logger.swift index 91cb9414..0cc78eaa 100644 --- a/Projects/SWMLogging/Sources/Logger.swift +++ b/Projects/SWMLogging/Sources/Logger.swift @@ -11,11 +11,11 @@ import Moya import CombineMoya import RxSwift -public protocol SWMLoggingScheme: Encodable{ +public protocol SWMLoggingScheme: Encodable { var eventLogName: String { get set } var screenName: String { get set } var logVersion: Int { get set } - var logData: [String: String] { get set } + var logData: [String: AnyEncodable] { get set } } extension SWMLoggingScheme { From 9ee979a87affb3edbbc2b887822e5c6c320c356b Mon Sep 17 00:00:00 2001 From: ddophi98 Date: Mon, 9 Oct 2023 15:09:29 +0900 Subject: [PATCH 08/10] =?UTF-8?q?[feat]=20rx=20=EC=93=B0=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EA=B3=A0=20throttle=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/SWMLogging/Sources/API.swift | 12 +++-- Projects/SWMLogging/Sources/Logger.swift | 59 +++++++++++------------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/Projects/SWMLogging/Sources/API.swift b/Projects/SWMLogging/Sources/API.swift index 8fc2ef31..2948c0cc 100644 --- a/Projects/SWMLogging/Sources/API.swift +++ b/Projects/SWMLogging/Sources/API.swift @@ -10,10 +10,10 @@ import Foundation import Moya struct LoggingAPI: TargetType { - let serverUrl: String - let serverPath: String - let authorization: String? = nil - var schemeData: Data = Data() + private let serverUrl: String + private let serverPath: String + private var authorization: String? + private var schemeData: Data = Data() public init(serverUrl: String, serverPath: String) { self.serverUrl = serverUrl @@ -24,6 +24,10 @@ struct LoggingAPI: TargetType { self.schemeData = schemeData } + public mutating func setAuthorization(_ authorization: String) { + self.authorization = authorization + } + var baseURL: URL { return URL(string: serverUrl)! } diff --git a/Projects/SWMLogging/Sources/Logger.swift b/Projects/SWMLogging/Sources/Logger.swift index 0cc78eaa..cd3f0600 100644 --- a/Projects/SWMLogging/Sources/Logger.swift +++ b/Projects/SWMLogging/Sources/Logger.swift @@ -9,7 +9,6 @@ import Foundation import Combine import Moya import CombineMoya -import RxSwift public protocol SWMLoggingScheme: Encodable { var eventLogName: String { get set } @@ -36,55 +35,53 @@ public class SWMLogger { static let encoder = JSONEncoder() private let moyaProvider = MoyaProvider() + private let throttleLimit = 1.0 private let sessionId = UUID() private let appVersion: String private let OSNameAndVersion: String + private var cancelBag = Set() private var loggingAPI: LoggingAPI - let disposeBag = DisposeBag() - public let hotObservable = PublishSubject() private var latestLogName = "" + private var latestShotTime = Date() public init(serverUrl: String, serverPath: String, OSNameAndVersion: String, appVersion: String) { self.OSNameAndVersion = OSNameAndVersion self.appVersion = appVersion loggingAPI = LoggingAPI(serverUrl: serverUrl, serverPath: serverPath) - hotObservable -// .flatMap({ scheme -> Observable in -// if scheme.eventLogName == self.latestLogName { -// return self.hotObservable -// .throttle(.seconds(1), scheduler: MainScheduler.instance) -// } else { -// return Observable.just(scheme) -// } -// }) - .subscribe(onNext: { scheme in - print("scheme", scheme) - self.latestLogName = scheme.eventLogName - }) - .disposed(by: disposeBag) } - // throw public func shotLogging(_ scheme: SWMLoggingScheme, authorization: String) throws { do { - hotObservable.onNext(scheme) - loggingAPI.setScheme(try scheme.makeJson()) - moyaProvider.requestPublisher(loggingAPI) - .sink(receiveCompletion: { result in - switch result { - case let .failure(error): - print(error) - default: break - } - }, receiveValue: { _ in - print("suceess") - }) - .store(in: &cancelBag) + if throttleCondition(scheme.eventLogName) { + latestShotTime = Date() + latestLogName = scheme.eventLogName + loggingAPI.setScheme(try scheme.makeJson()) + loggingAPI.setAuthorization(authorization) + sendRequest(loggingAPI) + } } catch { throw error } + } + private func throttleCondition(_ eventLogName: String) -> Bool { + (eventLogName == latestLogName && Date().timeIntervalSince(latestShotTime) > throttleLimit) || + (eventLogName != latestLogName) + } + + private func sendRequest(_ api: LoggingAPI) { + moyaProvider.requestPublisher(loggingAPI) + .sink(receiveCompletion: { result in + switch result { + case let .failure(error): + print(error) + default: break + } + }, receiveValue: { _ in + print("suceess") + }) + .store(in: &cancelBag) } } From 51d0c282bb8d812ce8e2e29816d587cead1535aa Mon Sep 17 00:00:00 2001 From: ddophi98 Date: Wed, 11 Oct 2023 12:16:21 +0900 Subject: [PATCH 09/10] =?UTF-8?q?[fix]=20=ED=94=BC=EB=93=9C=EB=B0=B1=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Domain/Sources/Logging/OrderClickedScheme.swift | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Projects/Domain/Sources/Logging/OrderClickedScheme.swift b/Projects/Domain/Sources/Logging/OrderClickedScheme.swift index e598a60e..19111bde 100644 --- a/Projects/Domain/Sources/Logging/OrderClickedScheme.swift +++ b/Projects/Domain/Sources/Logging/OrderClickedScheme.swift @@ -29,12 +29,6 @@ public struct OrderClickedScheme: ClickScheme { var userId: Int? var gender: String? var age: Int? - - public init(userId: Int? = nil, gender: String? = nil, age: Int? = nil) { - self.userId = userId - self.gender = gender - self.age = age - } public func setGender(gender: String) -> Builder { self.gender = gender @@ -44,6 +38,10 @@ public struct OrderClickedScheme: ClickScheme { self.age = age return self } + public func setUserId(userId: Int) -> Builder { + self.userId = userId + return self + } public func userId(id: Int) -> Builder { self.userId = id From dcd356e0c4cf46564ab57533addaaaa7f898be9f Mon Sep 17 00:00:00 2001 From: ddophi98 Date: Wed, 11 Oct 2023 13:31:39 +0900 Subject: [PATCH 10/10] =?UTF-8?q?[feat]=20LearningHome=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=EC=9D=98=20=EC=B6=94=EC=B2=9C=20=EB=AC=B8=EC=A0=9C,?= =?UTF-8?q?=20=ED=92=80=EB=8D=98=20=EB=AC=B8=EC=A0=9C=20=ED=81=B4=EB=A6=AD?= =?UTF-8?q?=20=EB=A1=9C=EA=B9=85=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/App/Sources/DI/DomainAssembly.swift | 2 +- Projects/App/Sources/LitoApp.swift | 5 +- ...gHomeRecommendedProblemClickedScheme.swift | 75 +++++++++++++++++ ...rningHomeSolvingProblemClickedScheme.swift | 82 +++++++++++++++++++ .../Sources/UseCase/LearningHomeUseCase.swift | 13 ++- .../UseCase/SovingProblemUseCase.swift | 11 --- .../LearningHome/LearningHomeViewModel.swift | 33 ++++++++ .../SolvingProblemListViewModel.swift | 11 --- .../SWMLogging/Sources/AnyEncodable.swift | 6 +- 9 files changed, 209 insertions(+), 29 deletions(-) create mode 100644 Projects/Domain/Sources/Logging/LearningHomeRecommendedProblemClickedScheme.swift create mode 100644 Projects/Domain/Sources/Logging/LearningHomeSolvingProblemClickedScheme.swift diff --git a/Projects/App/Sources/DI/DomainAssembly.swift b/Projects/App/Sources/DI/DomainAssembly.swift index f08b700a..8573214c 100644 --- a/Projects/App/Sources/DI/DomainAssembly.swift +++ b/Projects/App/Sources/DI/DomainAssembly.swift @@ -37,7 +37,7 @@ public struct DomainAssembly: Assembly { // ------------------------ First Tab ------------------------ container.register(LearningHomeUseCase.self) { resolver in let repository = resolver.resolve(ProblemRepository.self)! - return DefaultLearningHomeUseCase(repository: repository) + return DefaultLearningHomeUseCase(repository: repository, logger: logger) } container.register(ProblemDetailUseCase.self) { resolver in let repository = resolver.resolve(ProblemRepository.self)! diff --git a/Projects/App/Sources/LitoApp.swift b/Projects/App/Sources/LitoApp.swift index d1f317fb..8b4b1689 100644 --- a/Projects/App/Sources/LitoApp.swift +++ b/Projects/App/Sources/LitoApp.swift @@ -15,16 +15,13 @@ struct LitoApp: App { init() { UIFont.registerCommonFonts() let kakaoAppKey = Bundle.main.infoDictionary?["KAKAO_NATIVE_APP_KEY"] ?? "" - // Logging 객체 생성 - // Logging.init(mandatory 요소) KakaoSDK.initSDK(appKey: kakaoAppKey as! String) injector = DependencyInjector(container: Container()) toastHelper = ToastHelper() coordinator = Coordinator(.loginScene) - // OS NameAndVersion 기기에서 불러오기 + // TODO: 우리 서버 API에 맞게 주소 변경 필요 let logger = SWMLogger(serverUrl: "https://dev.swm-lgtm.com", serverPath: "/v1/log", OSNameAndVersion: "iOS 16", appVersion: "1.0") - // domainAssembly 에 Logging 객체 주입 injector.assemble([DomainAssembly(logger: logger), DataAssembly(), PresentationAssembly( diff --git a/Projects/Domain/Sources/Logging/LearningHomeRecommendedProblemClickedScheme.swift b/Projects/Domain/Sources/Logging/LearningHomeRecommendedProblemClickedScheme.swift new file mode 100644 index 00000000..f8f528f5 --- /dev/null +++ b/Projects/Domain/Sources/Logging/LearningHomeRecommendedProblemClickedScheme.swift @@ -0,0 +1,75 @@ +// +// ProblemClickedScheme.swift +// Domain +// +// Created by 김동락 on 2023/10/11. +// Copyright © 2023 com.lito. All rights reserved. +// + +import Foundation +import SWMLogging + +public struct LearningHomeRecommendedProblemClickedScheme: ClickScheme { + + public var eventLogName = "LearningHomeRecommendedProblemClicked" + public var screenName = "LearningHome" + public var logVersion = 1 + public var logData: [String: AnyEncodable] = [:] + + // 학습목표, 학습퍼센트, 풀던문제 존재 여부, 문제 id, 문제 카테고리, 문제 질문, 찜여부 + public init(learningGoal: Int?, learningPercent: Float?, isSolvingProblemExist: Bool?, problemId: Int?, problemCategory: String?, problemQuestion: String?, problemFavorite: Bool?) { + if let learningGoal = learningGoal { self.logData["learningGoal"] = .int(learningGoal)} + if let learningPercent = learningPercent { self.logData["learningPercent"] = .float(learningPercent)} + if let isSolvingProblemExist = isSolvingProblemExist { self.logData["isSolvingProblemExist"] = .bool(isSolvingProblemExist)} + if let problemId = problemId { self.logData["problemId"] = .int(problemId)} + if let problemCategory = problemCategory { self.logData["problemCategory"] = .string(problemCategory)} + if let problemQuestion = problemQuestion { self.logData["problemQuestion"] = .string(problemQuestion)} + if let problemFavorite = problemFavorite { self.logData["problemFavorite"] = .bool(problemFavorite)} + } + + public class Builder { + var learningGoal: Int? + var learningPercent: Float? + var isSolvingProblemExist: Bool? + var problemId: Int? + var problemCategory: String? + var problemQuestion: String? + var problemFavorite: Bool? + + public init() { } + + public func setLearningGoal(_ learningGoal: Int) -> Builder { + self.learningGoal = learningGoal + return self + } + public func setLearningPercent(_ learningPercent: Float) -> Builder { + self.learningPercent = learningPercent + return self + } + public func setIsSolvingProblemExist(_ isSolvingProblemExist: Bool) -> Builder { + self.isSolvingProblemExist = isSolvingProblemExist + return self + } + public func setProblemId(_ problemId: Int) -> Builder { + self.problemId = problemId + return self + } + public func setProblemCategory(_ problemCategory: String) -> Builder { + self.problemCategory = problemCategory + return self + } + public func setProblemQuestion(_ problemQuestion: String) -> Builder { + self.problemQuestion = problemQuestion + return self + } + public func setProblemFavorite(_ problemFavorite: Bool) -> Builder { + self.problemFavorite = problemFavorite + return self + } + public func build() -> SWMLoggingScheme { + return LearningHomeRecommendedProblemClickedScheme(learningGoal: learningGoal, learningPercent: learningPercent, isSolvingProblemExist: isSolvingProblemExist, problemId: problemId, problemCategory: problemCategory, problemQuestion: problemQuestion, problemFavorite: problemFavorite) + } + + } + +} diff --git a/Projects/Domain/Sources/Logging/LearningHomeSolvingProblemClickedScheme.swift b/Projects/Domain/Sources/Logging/LearningHomeSolvingProblemClickedScheme.swift new file mode 100644 index 00000000..e86bc746 --- /dev/null +++ b/Projects/Domain/Sources/Logging/LearningHomeSolvingProblemClickedScheme.swift @@ -0,0 +1,82 @@ +// +// LearningHomeSolvingProblemClickedScheme.swift +// Domain +// +// Created by 김동락 on 2023/10/11. +// Copyright © 2023 com.lito. All rights reserved. +// + +import Foundation +import SWMLogging + +public struct LearningHomeSolvingProblemClickedScheme: ClickScheme { + + public var eventLogName = "LearningHomeSolvingProblemClicked" + public var screenName = "LearningHome" + public var logVersion = 1 + public var logData: [String: AnyEncodable] = [:] + + // 학습목표, 학습퍼센트, 추천문제 개수, 추천문제 풀이한 개수, 문제 id, 문제 카테고리, 문제 질문, 찜여부 + public init(learningGoal: Int?, learningPercent: Float?, recommendedProblemsCount: Int?, recommendedProblemsSolvedCount: Int?, problemId: Int?, problemCategory: String?, problemQuestion: String?, problemFavorite: Bool?) { + if let learningGoal = learningGoal { self.logData["learningGoal"] = .int(learningGoal)} + if let learningPercent = learningPercent { self.logData["learningPercent"] = .float(learningPercent)} + if let recommendedProblemsCount = recommendedProblemsCount { self.logData["recommendedProblemsCount"] = .int(recommendedProblemsCount)} + if let recommendedProblemsSolvedCount = recommendedProblemsSolvedCount { self.logData["recommendedProblemsSolvedCount"] = .int(recommendedProblemsSolvedCount)} + if let problemId = problemId { self.logData["problemId"] = .int(problemId)} + if let problemCategory = problemCategory { self.logData["problemCategory"] = .string(problemCategory)} + if let problemQuestion = problemQuestion { self.logData["problemQuestion"] = .string(problemQuestion)} + if let problemFavorite = problemFavorite { self.logData["problemFavorite"] = .bool(problemFavorite)} + } + + public class Builder { + var learningGoal: Int? + var learningPercent: Float? + var recommendedProblemsCount: Int? + var recommendedProblemsSolvedCount: Int? + var problemId: Int? + var problemCategory: String? + var problemQuestion: String? + var problemFavorite: Bool? + + public init() { } + + public func setLearningGoal(_ learningGoal: Int) -> Builder { + self.learningGoal = learningGoal + return self + } + public func setLearningPercent(_ learningPercent: Float) -> Builder { + self.learningPercent = learningPercent + return self + } + public func setRecommendedProblemsCount(_ recommendedProblemsCount: Int) -> Builder { + self.recommendedProblemsCount = recommendedProblemsCount + return self + } + public func setrecommendedProblemsSolvedCount(_ recommendedProblemsSolvedCount: Int) -> Builder { + self.recommendedProblemsSolvedCount = recommendedProblemsSolvedCount + return self + } + public func setProblemId(_ problemId: Int) -> Builder { + self.problemId = problemId + return self + } + public func setProblemCategory(_ problemCategory: String) -> Builder { + self.problemCategory = problemCategory + return self + } + public func setProblemQuestion(_ problemQuestion: String) -> Builder { + self.problemQuestion = problemQuestion + return self + } + public func setProblemFavorite(_ problemFavorite: Bool) -> Builder { + self.problemFavorite = problemFavorite + return self + } + public func build() -> SWMLoggingScheme { + return LearningHomeSolvingProblemClickedScheme(learningGoal: learningGoal, learningPercent: learningPercent, recommendedProblemsCount: recommendedProblemsCount, recommendedProblemsSolvedCount: recommendedProblemsSolvedCount, problemId: problemId, problemCategory: problemCategory, problemQuestion: problemQuestion, problemFavorite: problemFavorite) + } + + } + +} + diff --git a/Projects/Domain/Sources/UseCase/LearningHomeUseCase.swift b/Projects/Domain/Sources/UseCase/LearningHomeUseCase.swift index 5464f954..34c586a6 100644 --- a/Projects/Domain/Sources/UseCase/LearningHomeUseCase.swift +++ b/Projects/Domain/Sources/UseCase/LearningHomeUseCase.swift @@ -8,19 +8,23 @@ import Combine import Foundation +import SWMLogging public protocol LearningHomeUseCase { func getProfileAndProblems() -> AnyPublisher func toggleProblemFavorite(id: Int) -> AnyPublisher func setProblemGoalCount(problemGoalCount: Int) func getProblemGoalCount() -> Int + func fireLogging(scheme: SWMLogging.SWMLoggingScheme) } public final class DefaultLearningHomeUseCase: LearningHomeUseCase { private let repository: ProblemRepository + private let logger: SWMLogger - public init(repository: ProblemRepository) { + public init(repository: ProblemRepository, logger: SWMLogger) { self.repository = repository + self.logger = logger } public func getProfileAndProblems() -> AnyPublisher { @@ -38,4 +42,11 @@ public final class DefaultLearningHomeUseCase: LearningHomeUseCase { public func getProblemGoalCount() -> Int { repository.getProblemGoalCount() } + public func fireLogging(scheme: SWMLogging.SWMLoggingScheme) { + do { + try logger.shotLogging(scheme, authorization: KeyChainManager.read(key: .accessToken) ?? "") + } catch { + + } + } } diff --git a/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift b/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift index 3d133eda..def5e345 100644 --- a/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift +++ b/Projects/Domain/Sources/UseCase/SovingProblemUseCase.swift @@ -13,20 +13,9 @@ import SWMLogging public protocol SolvingProblemListUseCase { func toggleProblemFavorite(id: Int) -> AnyPublisher func getProblemList(problemsQueryDTO: SolvingProblemsQueryDTO) -> AnyPublisher - func fireLogging(scheme: SWMLoggingScheme) } public final class DefaultSolvingProblemListUseCase: SolvingProblemListUseCase { - public func fireLogging(scheme: SWMLogging.SWMLoggingScheme) { - do { -// logger.hotObservable.onNext(scheme) - try logger.shotLogging(scheme, authorization: "eyJhbGciOiJIUzI1NiJ9.eyJnaXRodWJJZCI6Ikt4eEh5b1JpbSIsImlhdCI6MTY5NTcxNDE1MiwiZXhwIjoxNzI3MjUwMTUyfQ.tbQFKNIQCekhWZjHwOqQNBIY3YgXZZm-B95NyTvBn5c") - try logger.shotLogging(scheme, authorization: "eyJhbGciOiJIUzI1NiJ9.eyJnaXRodWJJZCI6Ikt4eEh5b1JpbSIsImlhdCI6MTY5NTcxNDE1MiwiZXhwIjoxNzI3MjUwMTUyfQ.tbQFKNIQCekhWZjHwOqQNBIY3YgXZZm-B95NyTvBn5c") - } catch { - - } - } - private let repository: ProblemRepository private let logger: SWMLogger diff --git a/Projects/Presentation/Sources/Views/LearningHome/LearningHomeViewModel.swift b/Projects/Presentation/Sources/Views/LearningHome/LearningHomeViewModel.swift index ba1e0ae2..871df2ce 100644 --- a/Projects/Presentation/Sources/Views/LearningHome/LearningHomeViewModel.swift +++ b/Projects/Presentation/Sources/Views/LearningHome/LearningHomeViewModel.swift @@ -68,11 +68,44 @@ public final class LearningHomeViewModel: BaseViewModel { .store(in: cancelBag) goalCount = useCase.getProblemGoalCount() } + + private func recommendedProblemClickedLogging(id: Int, index: Int) { + let scheme = LearningHomeRecommendedProblemClickedScheme.Builder() + .setLearningGoal(goalCount) + .setLearningPercent(learningRate) + .setIsSolvingProblemExist(learningHomeVO?.processProblem != nil) + .setProblemId(id) + .setProblemCategory(recommendProblems[index].subjectName) + .setProblemQuestion(recommendProblems[index].question) + .setProblemFavorite(recommendProblems[index].favorite == .favorite) + .build() + useCase.fireLogging(scheme: scheme) + } + + private func solvingProblemClickedSchemeLogging(id: Int) { + guard let processProblem = processProblem else { return } + let scheme = LearningHomeSolvingProblemClickedScheme.Builder() + .setLearningGoal(goalCount) + .setLearningPercent(learningRate) + .setRecommendedProblemsCount(recommendProblems.count) + .setrecommendedProblemsSolvedCount(recommendProblems.filter{$0.problemStatus == .solved}.count) + .setProblemId(id) + .setProblemCategory(processProblem.subjectName) + .setProblemQuestion(processProblem.question) + .setProblemFavorite(processProblem.favorite == .favorite) + .build() + useCase.fireLogging(scheme: scheme) + } } extension LearningHomeViewModel: ProblemCellHandling { // 해당 문제 풀이 화면으로 이동하기 public func onProblemCellClicked(id: Int) { coordinator.push(.problemDetailScene(id: id)) + if let index = self.recommendProblems.firstIndex(where: { $0.problemId == id}) { + recommendedProblemClickedLogging(id: id, index: index) + } else { + solvingProblemClickedSchemeLogging(id: id) + } } // 찜하기 or 찜해제하기 diff --git a/Projects/Presentation/Sources/Views/SolvingProblemList/SolvingProblemListViewModel.swift b/Projects/Presentation/Sources/Views/SolvingProblemList/SolvingProblemListViewModel.swift index 91318ef5..8371aae1 100644 --- a/Projects/Presentation/Sources/Views/SolvingProblemList/SolvingProblemListViewModel.swift +++ b/Projects/Presentation/Sources/Views/SolvingProblemList/SolvingProblemListViewModel.swift @@ -38,12 +38,6 @@ public final class SolvingProblemListViewModel: BaseViewModel { // 화면이 다시 떴을 때 혹시나 바뀌었을 값들을 위해 마지막으로 본 문제까지 전부 업데이트해주기 public func onScreenAppeared() { - - let orderClickedScheme = OrderClickedScheme.Builder() - .setAge(age: 0) - .setGender(gender: "man") - .build() - useCase.fireLogging(scheme: orderClickedScheme) lastNetworkAction = onScreenAppeared if problemCellList.isEmpty { return @@ -111,10 +105,5 @@ extension SolvingProblemListViewModel: ProblemCellHandling { self.problemCellList[index].favorite.toggle() }, errorHandler: errorHandler) .store(in: cancelBag) - let clickScheme = OrderClickedScheme.Builder() - .setAge(age: 0) - .setGender(gender: "0") - .build() - useCase.fireLogging(scheme: clickScheme) } } diff --git a/Projects/SWMLogging/Sources/AnyEncodable.swift b/Projects/SWMLogging/Sources/AnyEncodable.swift index f1efffa0..cde4d3bc 100644 --- a/Projects/SWMLogging/Sources/AnyEncodable.swift +++ b/Projects/SWMLogging/Sources/AnyEncodable.swift @@ -10,15 +10,19 @@ import Foundation // 필요한 encodable 타입 추가 가능 public enum AnyEncodable: Encodable { - case int(Int), string(String) + case bool(Bool), int(Int), string(String), float(Float) public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { + case .bool(let value): + try container.encode(value) case .int(let value): try container.encode(value) case .string(let value): try container.encode(value) + case .float(let value): + try container.encode(value) } } }