Skip to content

Commit 5cc6322

Browse files
committed
Add logic for logging start and end of important workers
Signed-off-by: Jonas Mayer <jonas.a.mayer@gmx.net>
1 parent 3f79f14 commit 5cc6322

15 files changed

Lines changed: 185 additions & 59 deletions

app/src/main/java/com/nextcloud/client/di/ComponentsModule.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@
2323
import com.nextcloud.client.documentscan.DocumentScanActivity;
2424
import com.nextcloud.client.editimage.EditImageActivity;
2525
import com.nextcloud.client.etm.EtmActivity;
26+
import com.nextcloud.client.etm.pages.EtmBackgroundJobsFragment;
2627
import com.nextcloud.client.files.downloader.FileTransferService;
28+
import com.nextcloud.client.jobs.BackgroundJobManagerImpl;
2729
import com.nextcloud.client.jobs.NotificationWork;
30+
import com.nextcloud.client.jobs.TestJob;
2831
import com.nextcloud.client.logger.ui.LogsActivity;
2932
import com.nextcloud.client.logger.ui.LogsViewModel;
3033
import com.nextcloud.client.media.PlayerService;
@@ -478,4 +481,13 @@ abstract class ComponentsModule {
478481

479482
@ContributesAndroidInjector
480483
abstract ImageDetailFragment imageDetailFragment();
484+
485+
@ContributesAndroidInjector
486+
abstract EtmBackgroundJobsFragment etmBackgroundJobsFragment();
487+
488+
@ContributesAndroidInjector
489+
abstract BackgroundJobManagerImpl backgroundJobManagerImpl();
490+
491+
@ContributesAndroidInjector
492+
abstract TestJob testJob();
481493
}

app/src/main/java/com/nextcloud/client/etm/pages/EtmBackgroundJobsFragment.kt

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121
package com.nextcloud.client.etm.pages
2222

23+
import android.annotation.SuppressLint
2324
import android.os.Bundle
2425
import android.view.LayoutInflater
2526
import android.view.Menu
@@ -32,15 +33,22 @@ import androidx.lifecycle.Observer
3233
import androidx.recyclerview.widget.DividerItemDecoration
3334
import androidx.recyclerview.widget.LinearLayoutManager
3435
import androidx.recyclerview.widget.RecyclerView
36+
import com.nextcloud.client.di.Injectable
3537
import com.nextcloud.client.etm.EtmBaseFragment
38+
import com.nextcloud.client.jobs.BackgroundJobManagerImpl
3639
import com.nextcloud.client.jobs.JobInfo
40+
import com.nextcloud.client.preferences.AppPreferences
3741
import com.owncloud.android.R
3842
import java.text.SimpleDateFormat
3943
import java.util.Locale
44+
import javax.inject.Inject
4045

41-
class EtmBackgroundJobsFragment : EtmBaseFragment() {
46+
class EtmBackgroundJobsFragment : EtmBaseFragment(), Injectable {
4247

43-
class Adapter(private val inflater: LayoutInflater) : RecyclerView.Adapter<Adapter.ViewHolder>() {
48+
@Inject
49+
lateinit var preferences : AppPreferences
50+
51+
class Adapter(private val inflater: LayoutInflater, private val preferences: AppPreferences) : RecyclerView.Adapter<Adapter.ViewHolder>(){
4452

4553
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
4654
val uuid = view.findViewById<TextView>(R.id.etm_background_job_uuid)
@@ -53,6 +61,7 @@ class EtmBackgroundJobsFragment : EtmBaseFragment() {
5361
val executionCount = view.findViewById<TextView>(R.id.etm_background_execution_count)
5462
val executionLog = view.findViewById<TextView>(R.id.etm_background_execution_logs)
5563
private val executionLogRow = view.findViewById<View>(R.id.etm_background_execution_logs_row)
64+
val executionTimesRow = view.findViewById<View>(R.id.etm_background_execution_times_row)
5665

5766
var progressEnabled: Boolean = progressRow.visibility == View.VISIBLE
5867
get() {
@@ -93,6 +102,7 @@ class EtmBackgroundJobsFragment : EtmBaseFragment() {
93102
val view = inflater.inflate(R.layout.etm_background_job_list_item, parent, false)
94103
val viewHolder = ViewHolder(view)
95104
viewHolder.logsEnabled = false
105+
viewHolder.executionTimesRow.visibility = View.GONE
96106
view.setOnClickListener {
97107
viewHolder.logsEnabled = !viewHolder.logsEnabled
98108
}
@@ -103,6 +113,7 @@ class EtmBackgroundJobsFragment : EtmBaseFragment() {
103113
return backgroundJobs.size
104114
}
105115

116+
@SuppressLint("SetTextI18n")
106117
override fun onBindViewHolder(vh: ViewHolder, position: Int) {
107118
val info = backgroundJobs[position]
108119
vh.uuid.text = info.id.toString()
@@ -116,8 +127,32 @@ class EtmBackgroundJobsFragment : EtmBaseFragment() {
116127
} else {
117128
vh.progressEnabled = false
118129
}
119-
vh.executionCount.text = "0"
120-
vh.executionLog.text = "None"
130+
131+
val logs = preferences.readLogEntry()
132+
val logsForThisWorker = logs.filter { BackgroundJobManagerImpl.parseTag(it.workerClass)?.second == info.workerClass }
133+
if(logsForThisWorker.isNotEmpty()) {
134+
vh.executionTimesRow.visibility = View.VISIBLE
135+
vh.executionCount.text = logsForThisWorker.filter { it.started != null }.size.toString() + " (${logsForThisWorker.filter { it.finished != null }.size})"
136+
var logText = "Worker Logs\n\n" +
137+
"*** Does NOT differentiate between imitate or periodic kinds of Work! ***\n"+
138+
"*** Times run in 48h: Times started (Times finished) ***\n"
139+
logsForThisWorker.forEach{
140+
logText += "----------------------\n"
141+
logText += "Worker ${BackgroundJobManagerImpl.parseTag(it.workerClass)?.second}\n"
142+
logText += if (it.started == null){
143+
"ENDED at\n${it.finished}\nWith result: ${it.result}\n"
144+
}else{
145+
"STARTED at\n${it.started}\n"
146+
}
147+
}
148+
vh.executionLog.text = logText
149+
}else{
150+
vh.executionLog.text = "Worker Logs\n\n" +
151+
"No Entries -> Maybe logging is not implemented for Worker or it has not run yet."
152+
vh.executionCount.text = "0"
153+
vh.executionTimesRow.visibility = View.GONE
154+
}
155+
121156
}
122157
}
123158

@@ -131,7 +166,7 @@ class EtmBackgroundJobsFragment : EtmBaseFragment() {
131166

132167
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
133168
val view = inflater.inflate(R.layout.fragment_etm_background_jobs, container, false)
134-
adapter = Adapter(inflater)
169+
adapter = Adapter(inflater, preferences)
135170
list = view.findViewById(R.id.etm_background_jobs_list)
136171
list.layoutManager = LinearLayoutManager(context)
137172
list.addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))

app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class BackgroundJobFactory @Inject constructor(
104104
FilesUploadWorker::class -> createFilesUploadWorker(context, workerParameters)
105105
GeneratePdfFromImagesWork::class -> createPDFGenerateWork(context, workerParameters)
106106
HealthStatusWork::class -> createHealthStatusWork(context, workerParameters)
107+
TestJob::class -> createTestJob(context, workerParameters)
107108
else -> null // caller falls back to default factory
108109
}
109110
}
@@ -142,7 +143,7 @@ class BackgroundJobFactory @Inject constructor(
142143
resources,
143144
arbitraryDataProvider,
144145
contentResolver,
145-
accountManager
146+
accountManager,
146147
)
147148
}
148149

@@ -151,7 +152,7 @@ class BackgroundJobFactory @Inject constructor(
151152
context,
152153
params,
153154
logger,
154-
contentResolver
155+
contentResolver,
155156
)
156157
}
157158

@@ -161,7 +162,7 @@ class BackgroundJobFactory @Inject constructor(
161162
params,
162163
contentResolver,
163164
accountManager,
164-
preferences
165+
preferences,
165166
)
166167
}
167168

@@ -170,7 +171,7 @@ class BackgroundJobFactory @Inject constructor(
170171
context,
171172
params,
172173
logger,
173-
contentResolver
174+
contentResolver,
174175
)
175176
}
176177

@@ -183,7 +184,8 @@ class BackgroundJobFactory @Inject constructor(
183184
uploadsStorageManager = uploadsStorageManager,
184185
connectivityService = connectivityService,
185186
powerManagementService = powerManagementService,
186-
syncedFolderProvider = syncedFolderProvider
187+
syncedFolderProvider = syncedFolderProvider,
188+
backgroundJobManager = backgroundJobManager.get()
187189
)
188190
}
189191

@@ -208,7 +210,7 @@ class BackgroundJobFactory @Inject constructor(
208210
preferences,
209211
clock,
210212
viewThemeUtils.get(),
211-
syncedFolderProvider
213+
syncedFolderProvider,
212214
)
213215
}
214216

@@ -219,7 +221,7 @@ class BackgroundJobFactory @Inject constructor(
219221
notificationManager,
220222
accountManager,
221223
deckApi,
222-
viewThemeUtils.get()
224+
viewThemeUtils.get(),
223225
)
224226
}
225227

@@ -245,8 +247,9 @@ class BackgroundJobFactory @Inject constructor(
245247
accountManager,
246248
viewThemeUtils.get(),
247249
localBroadcastManager.get(),
250+
backgroundJobManager.get(),
248251
context,
249-
params
252+
params,
250253
)
251254
}
252255

@@ -258,7 +261,7 @@ class BackgroundJobFactory @Inject constructor(
258261
notificationManager = notificationManager,
259262
userAccountManager = accountManager,
260263
logger = logger,
261-
params = params
264+
params = params,
262265
)
263266
}
264267

@@ -267,7 +270,16 @@ class BackgroundJobFactory @Inject constructor(
267270
context,
268271
params,
269272
accountManager,
270-
arbitraryDataProvider
273+
arbitraryDataProvider,
274+
backgroundJobManager.get()
275+
)
276+
}
277+
278+
private fun createTestJob(context: Context, params: WorkerParameters): TestJob {
279+
return TestJob(
280+
context,
281+
params,
282+
backgroundJobManager.get()
271283
)
272284
}
273285
}

app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package com.nextcloud.client.jobs
2121

2222
import androidx.lifecycle.LiveData
23+
import androidx.work.ListenableWorker
2324
import com.nextcloud.client.account.User
2425
import com.owncloud.android.datamodel.OCFile
2526

@@ -35,6 +36,10 @@ interface BackgroundJobManager {
3536
*/
3637
val jobs: LiveData<List<JobInfo>>
3738

39+
fun logStartOfWorker(workerName : String?)
40+
41+
fun logEndOfWorker(workerName: String?, result: ListenableWorker.Result)
42+
3843
/**
3944
* Start content observer job that monitors changes in media folders
4045
* and launches synchronization when needed.

app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,13 @@ import androidx.work.WorkManager
3636
import androidx.work.workDataOf
3737
import com.nextcloud.client.account.User
3838
import com.nextcloud.client.core.Clock
39+
import com.nextcloud.client.di.Injectable
3940
import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork
4041
import com.nextcloud.client.preferences.AppPreferences
4142
import com.owncloud.android.datamodel.OCFile
42-
import java.time.LocalDate
4343
import java.util.Date
4444
import java.util.UUID
4545
import java.util.concurrent.TimeUnit
46-
import javax.inject.Inject
4746
import kotlin.reflect.KClass
4847

4948
/**
@@ -63,11 +62,10 @@ import kotlin.reflect.KClass
6362
@Suppress("TooManyFunctions") // we expect this implementation to have rich API
6463
internal class BackgroundJobManagerImpl(
6564
private val workManager: WorkManager,
66-
private val clock: Clock
67-
) : BackgroundJobManager {
65+
private val clock: Clock,
66+
private val preferences: AppPreferences
67+
) : BackgroundJobManager, Injectable {
6868

69-
@Inject
70-
private var preferences: AppPreferences? = null
7169

7270
companion object {
7371

@@ -89,6 +87,7 @@ internal class BackgroundJobManagerImpl(
8987
const val JOB_PDF_GENERATION = "pdf_generation"
9088
const val JOB_IMMEDIATE_CALENDAR_BACKUP = "immediate_calendar_backup"
9189
const val JOB_IMMEDIATE_FILES_EXPORT = "immediate_files_export"
90+
9291
const val JOB_PERIODIC_HEALTH_STATUS = "periodic_health_status"
9392
const val JOB_IMMEDIATE_HEALTH_STATUS = "immediate_health_status"
9493

@@ -98,8 +97,9 @@ internal class BackgroundJobManagerImpl(
9897

9998
const val TAG_PREFIX_NAME = "name"
10099
const val TAG_PREFIX_USER = "user"
100+
const val TAG_PREFIX_CLASS = "class"
101101
const val TAG_PREFIX_START_TIMESTAMP = "timestamp"
102-
val PREFIXES = setOf(TAG_PREFIX_NAME, TAG_PREFIX_USER, TAG_PREFIX_START_TIMESTAMP)
102+
val PREFIXES = setOf(TAG_PREFIX_NAME, TAG_PREFIX_USER, TAG_PREFIX_START_TIMESTAMP, TAG_PREFIX_CLASS)
103103
const val NOT_SET_VALUE = "not set"
104104
const val PERIODIC_BACKUP_INTERVAL_MINUTES = 24 * 60L
105105
const val DEFAULT_PERIODIC_JOB_INTERVAL_MINUTES = 15L
@@ -116,6 +116,7 @@ internal class BackgroundJobManagerImpl(
116116
}
117117

118118
fun formatUserTag(user: User): String = "$TAG_PREFIX_USER:${user.accountName}"
119+
fun formatClassTag(jobClass: KClass<out ListenableWorker>): String = "$TAG_PREFIX_CLASS:${jobClass.simpleName}"
119120
fun formatTimeTag(startTimestamp: Long): String = "$TAG_PREFIX_START_TIMESTAMP:$startTimestamp"
120121

121122
fun parseTag(tag: String): Pair<String, String>? {
@@ -153,6 +154,7 @@ internal class BackgroundJobManagerImpl(
153154
user = metadata.get(TAG_PREFIX_USER) ?: NOT_SET_VALUE,
154155
started = timestamp,
155156
progress = info.progress.getInt("progress", -1),
157+
workerClass = metadata.get(TAG_PREFIX_CLASS) ?: NOT_SET_VALUE
156158
)
157159
} else {
158160
null
@@ -162,8 +164,11 @@ internal class BackgroundJobManagerImpl(
162164
fun deleteOldLogs(logEntries: MutableList<LogEntry>) : MutableList<LogEntry>{
163165

164166
logEntries.removeIf {
165-
return@removeIf it.started != null &&
166-
Date(Date().time - KEEP_LOG_MILLIS).before(it.started)
167+
return@removeIf (it.started != null &&
168+
Date(Date().time - KEEP_LOG_MILLIS).after(it.started)) ||
169+
(it.finished != null &&
170+
Date(Date().time - KEEP_LOG_MILLIS).after(it.finished))
171+
167172
}
168173
return logEntries
169174

@@ -172,13 +177,27 @@ internal class BackgroundJobManagerImpl(
172177

173178
}
174179

175-
fun logStartOfWorker(workerName : String){
176-
if (preferences == null) return;
180+
override fun logStartOfWorker(workerName : String?) {
181+
val logs = deleteOldLogs(preferences.readLogEntry().toMutableList())
177182

178-
preferences!!.readLogEntry()
183+
if (workerName == null) {
184+
logs.add(LogEntry(Date(), null, null, NOT_SET_VALUE))
185+
}else{
186+
logs.add(LogEntry(Date(), null, null, workerName))
187+
}
188+
preferences.saveLogEntry(logs)
179189
}
180190

181-
fun logEndOfWorker(workerName: String)
191+
override fun logEndOfWorker(workerName: String?, result: ListenableWorker.Result){
192+
193+
val logs = deleteOldLogs(preferences.readLogEntry().toMutableList())
194+
if (workerName == null) {
195+
logs.add(LogEntry(null,Date(),result.toString(), NOT_SET_VALUE))
196+
}else{
197+
logs.add(LogEntry(null,Date(),result.toString(),workerName))
198+
}
199+
preferences.saveLogEntry(logs)
200+
}
182201

183202
/**
184203
* Create [OneTimeWorkRequest.Builder] pre-set with common attributes
@@ -192,6 +211,7 @@ internal class BackgroundJobManagerImpl(
192211
.addTag(TAG_ALL)
193212
.addTag(formatNameTag(jobName, user))
194213
.addTag(formatTimeTag(clock.currentTime))
214+
.addTag(formatClassTag(jobClass))
195215
user?.let { builder.addTag(formatUserTag(it)) }
196216
return builder
197217
}
@@ -216,6 +236,7 @@ internal class BackgroundJobManagerImpl(
216236
.addTag(TAG_ALL)
217237
.addTag(formatNameTag(jobName, user))
218238
.addTag(formatTimeTag(clock.currentTime))
239+
.addTag(formatClassTag(jobClass))
219240
user?.let { builder.addTag(formatUserTag(it)) }
220241
return builder
221242
}

0 commit comments

Comments
 (0)