| // Copyright 2023 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package upload |
| |
| import ( |
| "os" |
| "path/filepath" |
| "strings" |
| ) |
| |
| // files to handle |
| type work struct { |
| // absolute file names |
| countfiles []string // count files to process |
| readyfiles []string // old reports to upload |
| // relative names |
| uploaded map[string]bool // reports that have been uploaded |
| } |
| |
| // find all the files that look like counter files or reports |
| // that need to be uploaded. (There may be unexpected leftover files |
| // and uploading is supposed to be idempotent.) |
| func (u *uploader) findWork() work { |
| localdir, uploaddir := u.dir.LocalDir(), u.dir.UploadDir() |
| var ans work |
| fis, err := os.ReadDir(localdir) |
| if err != nil { |
| u.logger.Printf("Could not find work: failed to read local dir %s: %v", localdir, err) |
| return ans |
| } |
| |
| mode, asof := u.dir.Mode() |
| u.logger.Printf("Finding work: mode %s asof %s", mode, asof) |
| |
| // count files end in .v1.count |
| // reports end in .json. If they are not to be uploaded they |
| // start with local. |
| for _, fi := range fis { |
| if strings.HasSuffix(fi.Name(), ".v1.count") { |
| fname := filepath.Join(localdir, fi.Name()) |
| _, expiry, err := u.counterDateSpan(fname) |
| switch { |
| case err != nil: |
| u.logger.Printf("Error reading expiry for count file %s: %v", fi.Name(), err) |
| case expiry.After(u.startTime): |
| u.logger.Printf("Skipping count file %s: still active", fi.Name()) |
| default: |
| u.logger.Printf("Collecting count file %s", fi.Name()) |
| ans.countfiles = append(ans.countfiles, fname) |
| } |
| } else if strings.HasPrefix(fi.Name(), "local.") { |
| // skip |
| } else if strings.HasSuffix(fi.Name(), ".json") && mode == "on" { |
| // Collect reports that are ready for upload. |
| reportDate := u.uploadReportDate(fi.Name()) |
| if !asof.IsZero() && !reportDate.IsZero() { |
| // If both the mode asof date and the report date are present, do the |
| // right thing... |
| // |
| // (see https://github.com/golang/go/issues/63142#issuecomment-1734025130) |
| if asof.Before(reportDate) { |
| // Note: since this report was created after telemetry was enabled, |
| // we can only assume that the process that created it checked that |
| // the counter data contained therein was all from after the asof |
| // date. |
| // |
| // TODO(rfindley): store the begin date in reports, so that we can |
| // verify this assumption. |
| u.logger.Printf("Uploadable: %s", fi.Name()) |
| ans.readyfiles = append(ans.readyfiles, filepath.Join(localdir, fi.Name())) |
| } |
| } else { |
| // ...otherwise fall back on the old behavior of uploading all |
| // unuploaded files. |
| // |
| // TODO(rfindley): invert this logic following more testing. We |
| // should only upload if we know both the asof date and the report |
| // date, and they are acceptable. |
| u.logger.Printf("Uploadable (missing date): %s", fi.Name()) |
| ans.readyfiles = append(ans.readyfiles, filepath.Join(localdir, fi.Name())) |
| } |
| } |
| } |
| |
| fis, err = os.ReadDir(uploaddir) |
| if err != nil { |
| os.MkdirAll(uploaddir, 0777) |
| return ans |
| } |
| // There should be only one of these per day; maybe sometime |
| // we'll want to clean the directory. |
| ans.uploaded = make(map[string]bool) |
| for _, fi := range fis { |
| if strings.HasSuffix(fi.Name(), ".json") { |
| u.logger.Printf("Already uploaded: %s", fi.Name()) |
| ans.uploaded[fi.Name()] = true |
| } |
| } |
| return ans |
| } |