Skip to content

Commit 3250637

Browse files
authored
chore(logger): handling for previous session logs implemented (#250)
* previous logs session header added * search fix
1 parent 944340f commit 3250637

File tree

11 files changed

+109
-52
lines changed

11 files changed

+109
-52
lines changed

pluto-plugins/plugins/logger/lib/src/main/java/com/pluto/plugins/logger/internal/DataModel.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ internal data class LogData(
3535
val timeStamp: Long = System.currentTimeMillis()
3636
) : ListItem()
3737

38+
@Keep
39+
internal data class LogPreviousSessionHeader(
40+
val label: String = "header"
41+
) : ListItem()
42+
3843
@Keep
3944
@JsonClass(generateAdapter = true)
4045
internal data class StackTrace(

pluto-plugins/plugins/logger/lib/src/main/java/com/pluto/plugins/logger/internal/LogsViewModel.kt

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@ import androidx.lifecycle.LiveData
66
import androidx.lifecycle.MutableLiveData
77
import androidx.lifecycle.viewModelScope
88
import com.pluto.plugins.logger.internal.persistence.LogDBHandler
9+
import com.pluto.plugins.logger.internal.persistence.LogEntity
910
import com.pluto.utilities.extensions.asFormattedDate
11+
import com.pluto.utilities.list.ListItem
1012
import kotlinx.coroutines.Dispatchers
1113
import kotlinx.coroutines.launch
1214

1315
internal class LogsViewModel(application: Application) : AndroidViewModel(application) {
1416

15-
val logs: LiveData<List<LogData>>
17+
private var rawLogs: List<LogEntity>? = null
18+
val logs: LiveData<List<ListItem>>
1619
get() = _logs
17-
private val _logs = MutableLiveData<List<LogData>>()
20+
private val _logs = MutableLiveData<List<ListItem>>()
1821

1922
val current: LiveData<LogData>
2023
get() = _current
@@ -24,9 +27,20 @@ internal class LogsViewModel(application: Application) : AndroidViewModel(applic
2427
get() = _serializedLogs
2528
private val _serializedLogs = MutableLiveData<String>()
2629

27-
fun fetchAll() {
30+
fun fetch(search: String = "") {
2831
viewModelScope.launch(Dispatchers.IO) {
29-
val list = LogDBHandler.fetchAll()?.map { it.data } ?: arrayListOf()
32+
if (rawLogs == null) {
33+
rawLogs = LogDBHandler.fetchAll()
34+
}
35+
val currentSessionLogs = (rawLogs ?: arrayListOf()).filter { it.sessionId == Session.id && it.data.isValidSearch(search) }.map { it.data }
36+
val previousSessionLogs = (rawLogs ?: arrayListOf()).filter { it.sessionId != Session.id && it.data.isValidSearch(search) }.map { it.data }
37+
38+
val list = arrayListOf<ListItem>()
39+
list.addAll(currentSessionLogs)
40+
if (previousSessionLogs.isNotEmpty()) {
41+
list.add(LogPreviousSessionHeader())
42+
list.addAll(previousSessionLogs)
43+
}
3044
_logs.postValue(list)
3145
}
3246
}
@@ -47,22 +61,24 @@ internal class LogsViewModel(application: Application) : AndroidViewModel(applic
4761
val text = StringBuilder()
4862
text.append("Pluto Log Trace")
4963
logs.value?.forEach {
50-
text.append("\n----------\n")
51-
text.append("${it.timeStamp.asFormattedDate(DATE_FORMAT)} ${it.level.label.uppercase()} | ${it.tag}: ${it.message}")
52-
it.tr?.let { tr ->
53-
text.append("\n\tException: ${tr}\n")
54-
tr.stackTrace.take(MAX_STACK_TRACE_LINES).forEach { trace ->
55-
text.append("\t\t at $trace\n")
56-
}
57-
if (tr.stackTrace.size - MAX_STACK_TRACE_LINES > 0) {
58-
text.append("\t\t + ${tr.stackTrace.size - MAX_STACK_TRACE_LINES} more lines")
64+
if (it is LogData) {
65+
text.append("\n----------\n")
66+
text.append("${it.timeStamp.asFormattedDate(DATE_FORMAT)} ${it.level.label.uppercase()} | ${it.tag}: ${it.message}")
67+
it.tr?.let { tr ->
68+
text.append("\n\tException: ${tr}\n")
69+
tr.stackTrace.take(MAX_STACK_TRACE_LINES).forEach { trace ->
70+
text.append("\t\t at $trace\n")
71+
}
72+
if (tr.stackTrace.size - MAX_STACK_TRACE_LINES > 0) {
73+
text.append("\t\t + ${tr.stackTrace.size - MAX_STACK_TRACE_LINES} more lines")
74+
}
5975
}
60-
}
61-
it.eventAttributes?.let { attr ->
62-
if (attr.isNotEmpty()) {
63-
text.append("\n\tEvent Attributes (${attr.size}):")
64-
attr.forEach { entry ->
65-
text.append("\n\t\t${entry.key}: ${entry.value}")
76+
it.eventAttributes?.let { attr ->
77+
if (attr.isNotEmpty()) {
78+
text.append("\n\tEvent Attributes (${attr.size}):")
79+
attr.forEach { entry ->
80+
text.append("\n\t\t${entry.key}: ${entry.value}")
81+
}
6682
}
6783
}
6884
}
@@ -76,3 +92,6 @@ internal class LogsViewModel(application: Application) : AndroidViewModel(applic
7692
const val DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS"
7793
}
7894
}
95+
96+
private fun LogData.isValidSearch(search: String): Boolean =
97+
search.isEmpty() || tag.contains(search, true) || message.contains(search, true) || stackTrace.fileName.contains(search, true)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.pluto.plugins.logger.internal
22

3+
import java.util.UUID
4+
35
internal object Session {
6+
val id: String = UUID.randomUUID().toString()
47
var loggerSearchText: String? = null
58
}

pluto-plugins/plugins/logger/lib/src/main/java/com/pluto/plugins/logger/internal/persistence/LogDBHandler.kt

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,14 @@ internal object LogDBHandler {
2828

2929
fun persistLog(level: Level, tag: String, message: String?, tr: Throwable?, ele: StackTrace) {
3030
coroutineScope.launch {
31-
val logEntity = LogEntity(
32-
timestamp = System.currentTimeMillis(),
33-
data = LogData(level, tag, message ?: "", tr?.asExceptionData(), ele)
34-
)
31+
val logEntity = LogEntity(data = LogData(level, tag, message ?: "", tr?.asExceptionData(), ele))
3532
logDao?.save(logEntity) ?: run { pushToTempList(logEntity) }
3633
}
3734
}
3835

3936
fun persistEvent(level: Level, tag: String, event: String, attr: HashMap<String, Any?>?, ele: StackTrace) {
4037
coroutineScope.launch {
41-
val logEntity = LogEntity(
42-
timestamp = System.currentTimeMillis(),
43-
data = LogData(level, tag, event, null, ele, attr)
44-
)
38+
val logEntity = LogEntity(data = LogData(level, tag, event, null, ele, attr))
4539
logDao?.save(logEntity) ?: run { pushToTempList(logEntity) }
4640
}
4741
}

pluto-plugins/plugins/logger/lib/src/main/java/com/pluto/plugins/logger/internal/persistence/LogEntity.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import androidx.room.Entity
66
import androidx.room.PrimaryKey
77
import androidx.room.TypeConverters
88
import com.pluto.plugins.logger.internal.LogData
9-
import com.pluto.utilities.list.ListItem
9+
import com.pluto.plugins.logger.internal.Session
1010
import com.squareup.moshi.JsonClass
1111

1212
@Keep
@@ -17,8 +17,10 @@ internal data class LogEntity(
1717
@PrimaryKey(autoGenerate = true)
1818
@ColumnInfo(name = "id")
1919
val id: Int? = null,
20+
@ColumnInfo(name = "session_id")
21+
val sessionId: String = Session.id,
2022
@ColumnInfo(name = "timestamp")
21-
val timestamp: Long,
23+
val timestamp: Long = System.currentTimeMillis(),
2224
@ColumnInfo(name = "data")
2325
val data: LogData,
24-
) : ListItem()
26+
)

pluto-plugins/plugins/logger/lib/src/main/java/com/pluto/plugins/logger/internal/persistence/database/PlutoDatabase.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import com.pluto.plugins.logger.internal.persistence.LogEntity
88
entities = [
99
LogEntity::class,
1010
],
11-
version = 1,
11+
version = 2,
1212
exportSchema = false
1313
)
1414
internal abstract class PlutoDatabase : RoomDatabase() {

pluto-plugins/plugins/logger/lib/src/main/java/com/pluto/plugins/logger/internal/ui/ListFragment.kt

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ internal class ListFragment : Fragment(R.layout.pluto_logger___fragment_list) {
4646
viewLifecycleOwner.lifecycleScope.launchWhenResumed {
4747
text?.toString()?.let {
4848
Session.loggerSearchText = it
49-
logsAdapter.list = filteredLogs(it)
49+
viewModel.fetch(it)
5050
if (it.isEmpty()) {
5151
binding.logList.linearLayoutManager()?.scrollToPositionWithOffset(0, 0)
5252
}
@@ -57,7 +57,7 @@ internal class ListFragment : Fragment(R.layout.pluto_logger___fragment_list) {
5757
viewModel.logs.removeObserver(logsObserver)
5858
viewModel.logs.observe(viewLifecycleOwner, logsObserver)
5959

60-
viewModel.fetchAll()
60+
viewModel.fetch()
6161

6262
viewModel.serializedLogs.removeObserver(serializedLogsObserver)
6363
viewModel.serializedLogs.observe(viewLifecycleOwner, serializedLogsObserver)
@@ -70,7 +70,7 @@ internal class ListFragment : Fragment(R.layout.pluto_logger___fragment_list) {
7070
when (item.itemId) {
7171
R.id.clear -> viewModel.deleteAll()
7272
R.id.shareAll ->
73-
if (viewModel.logs.value?.size ?: 0 > 0) {
73+
if (!viewModel.logs.value.isNullOrEmpty()) {
7474
viewModel.serializeLogs()
7575
} else {
7676
context?.toast("No logs to share")
@@ -80,30 +80,16 @@ internal class ListFragment : Fragment(R.layout.pluto_logger___fragment_list) {
8080
}
8181
}
8282

83-
@Synchronized
84-
private fun filteredLogs(search: String): List<LogData> {
85-
val list = arrayListOf<LogData>()
86-
.apply {
87-
viewModel.logs.value?.let { addAll(it) }
88-
}
89-
.filter { log ->
90-
log.tag.contains(search, true) ||
91-
log.message.contains(search, true) ||
92-
log.stackTrace.fileName.contains(search, true)
93-
}
83+
private val logsObserver = Observer<List<ListItem>> {
84+
logsAdapter.list = it
9485
binding.noItemText.text = getString(
95-
if (search.isNotEmpty()) {
86+
if (binding.search.text.toString().isNotEmpty()) {
9687
R.string.pluto_logger___no_search_result
9788
} else {
9889
R.string.pluto_logger___no_logs_text
9990
}
10091
)
101-
binding.noItemText.visibility = if (list.isEmpty()) View.VISIBLE else View.GONE
102-
return list
103-
}
104-
105-
private val logsObserver = Observer<List<LogData>> {
106-
logsAdapter.list = filteredLogs(binding.search.text.toString())
92+
binding.noItemText.visibility = if (it.isEmpty()) View.VISIBLE else View.GONE
10793
}
10894

10995
private val serializedLogsObserver = Observer<String> {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.pluto.plugins.logger.internal.ui.list
2+
3+
import android.view.ViewGroup
4+
import com.pluto.plugins.logger.R
5+
import com.pluto.plugins.logger.databinding.PlutoLoggerListHeaderBinding
6+
import com.pluto.utilities.extensions.inflate
7+
import com.pluto.utilities.list.DiffAwareAdapter
8+
import com.pluto.utilities.list.DiffAwareHolder
9+
import com.pluto.utilities.list.ListItem
10+
11+
internal class LogHeaderHolder(parent: ViewGroup, actionListener: DiffAwareAdapter.OnActionListener) :
12+
DiffAwareHolder(parent.inflate(R.layout.pluto_logger___list_header), actionListener) {
13+
14+
private val binding = PlutoLoggerListHeaderBinding.bind(itemView)
15+
private val logTag = binding.title
16+
17+
override fun onBind(item: ListItem) {
18+
logTag.text = context.getString(R.string.pluto_logger___previous_log_header)
19+
}
20+
}

pluto-plugins/plugins/logger/lib/src/main/java/com/pluto/plugins/logger/internal/ui/list/LogsAdapter.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.pluto.plugins.logger.internal.ui.list
22

33
import android.view.ViewGroup
44
import com.pluto.plugins.logger.internal.LogData
5+
import com.pluto.plugins.logger.internal.LogPreviousSessionHeader
56
import com.pluto.utilities.list.BaseAdapter
67
import com.pluto.utilities.list.DiffAwareHolder
78
import com.pluto.utilities.list.ListItem
@@ -10,18 +11,21 @@ internal class LogsAdapter(private val listener: OnActionListener) : BaseAdapter
1011
override fun getItemViewType(item: ListItem): Int? {
1112
return when (item) {
1213
is LogData -> ITEM_TYPE_LOG
14+
is LogPreviousSessionHeader -> ITEM_TYPE_HEADER
1315
else -> null
1416
}
1517
}
1618

1719
override fun onViewHolderCreated(parent: ViewGroup, viewType: Int): DiffAwareHolder? {
1820
return when (viewType) {
1921
ITEM_TYPE_LOG -> LogItemHolder(parent, listener)
22+
ITEM_TYPE_HEADER -> LogHeaderHolder(parent, listener)
2023
else -> null
2124
}
2225
}
2326

2427
companion object {
2528
const val ITEM_TYPE_LOG = 1000
29+
const val ITEM_TYPE_HEADER = 1001
2630
}
2731
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
xmlns:tools="http://schemas.android.com/tools"
5+
android:layout_width="match_parent"
6+
android:layout_height="wrap_content"
7+
android:background="@color/pluto___dark_10">
8+
9+
<TextView
10+
android:id="@+id/title"
11+
android:layout_width="0dp"
12+
android:layout_height="wrap_content"
13+
android:layout_marginVertical="@dimen/pluto___margin_xsmall"
14+
android:layout_marginHorizontal="@dimen/pluto___margin_small"
15+
android:fontFamily="@font/muli_semibold"
16+
android:textColor="@color/pluto___text_dark_80"
17+
android:textSize="@dimen/pluto___text_xsmall"
18+
app:layout_constraintStart_toStartOf="parent"
19+
app:layout_constraintTop_toTopOf="parent"
20+
app:layout_constraintBottom_toBottomOf="parent"
21+
tools:text="log tag" />
22+
23+
</androidx.constraintlayout.widget.ConstraintLayout>

0 commit comments

Comments
 (0)