Synchronization Troubleshooting - Bugreport and feature request

Dear DHS2 Team,

We started to use the new Synchronization Troubleshooting, which is really great to follow-up android synchronization issues.

However, we have been facing 2 issues during the tests, and I was wondering if we should create a feature request/bug report, or may be this is already in the road map:

  1. The application does not manage to display the errors when there are 2 many events in error. This is due to one one of the request from the app, which tries to fetch all events with sync errors (. The response is “header too large” when there are too many events.
    the request looks like this
    /api/41/tracker/events?event=Event1_UID%3BEvent1_UID%3Event3_UID%3BEvent4_UID%3BEvent5_UID%3BEvent6_UID%3BEvent7_UID… Etc

  2. In order to give access to the “synchronization troubleshoot” application, I had to grant the authority “F_JOB_LOG_READ” to the users.
    They have access to the logs, through the app, however, they see all the logs, from all the programs, from all the OUs.
    In order to decentralize the sync troubleshoot, it would be really nice to enable each user to only see the logs from the OUs or programs that are assigned to them.

I remain available to clarify if needed.

Thanks in advance and have a very good day.

2 Likes

Hi again,

Aditionally, as a feature idea for a potential future version, this would be really awesome to have the possibilty to build some kind of reports/Dashboards based on the errors displayed by the app “Sync troubleshoot”.

For instance, I extracted the “errors.json” obtained from Web Dev Tools, converted it to CSV, and then I am able to compute the numer of errors per user and per error code to get an overview of the most frequent problems regarding sync.

Hi,

Just to share a tip, for those using TaskR to execute javascript codes, below is an example to build a table containing usernames, error types, error messages for the errors log:

const api = await dhis2.api();
// Step 1: Fetch job configuration errors
const backlogs = await api.get(“jobConfigurations/errors”, {
paging: false
});

// Step 2: Extract unique user IDs
const userIds = […new Set(backlogs.map(job => job.user))];

// Step 3: Fetch user details in bulk
const userDetails = await Promise.all(
userIds.map(async userId => {
const user = await api.get(users/${userId});
return {
id: userId,
username: user.displayName || user.name || user.username
};
})
);

// Step 4: Create a lookup map for user IDs to usernames
const userMap = Object.fromEntries(
userDetails.map(user => [user.id, user.username])
);

// Step 5: Flatten and enrich the errors
const flattenedErrors = backlogs.flatMap(job =>
(job.errors || ).map(error => ({
jobId: job.id,
created: job.created,
user: userMap[job.user] || job.user, // fallback to ID if name not found
errorId: error.id,
errorMessage: error.message,
code: error.code,
type: error.type,
args: error.args
}))
);

return flattenedErrors;