github.com/mrqzzz/migrate@v5.1.7+incompatible/migrate.go (about) 1 // Package migrate reads migrations from sources and runs them against databases. 2 // Sources are defined by the `source.Driver` and databases by the `database.Driver` 3 // interface. The driver interfaces are kept "dump", all migration logic is kept 4 // in this package. 5 package migrate 6 7 import ( 8 "errors" 9 "fmt" 10 "os" 11 "sync" 12 "time" 13 14 "github.com/golang-migrate/migrate/v4/database" 15 "github.com/golang-migrate/migrate/v4/source" 16 ) 17 18 // DefaultPrefetchMigrations sets the number of migrations to pre-read 19 // from the source. This is helpful if the source is remote, but has little 20 // effect for a local source (i.e. file system). 21 // Please note that this setting has a major impact on the memory usage, 22 // since each pre-read migration is buffered in memory. See DefaultBufferSize. 23 var DefaultPrefetchMigrations = uint(10) 24 25 // DefaultLockTimeout sets the max time a database driver has to acquire a lock. 26 var DefaultLockTimeout = 15 * time.Second 27 28 var ( 29 ErrNoChange = errors.New("no change") 30 ErrNilVersion = errors.New("no migration") 31 ErrInvalidVersion = errors.New("version must be >= -1") 32 ErrLocked = errors.New("database locked") 33 ErrLockTimeout = errors.New("timeout: can't acquire database lock") 34 ) 35 36 // ErrShortLimit is an error returned when not enough migrations 37 // can be returned by a source for a given limit. 38 type ErrShortLimit struct { 39 Short uint 40 } 41 42 // Error implements the error interface. 43 func (e ErrShortLimit) Error() string { 44 return fmt.Sprintf("limit %v short", e.Short) 45 } 46 47 type ErrDirty struct { 48 Version int 49 } 50 51 func (e ErrDirty) Error() string { 52 return fmt.Sprintf("Dirty database version %v. Fix and force version.", e.Version) 53 } 54 55 type Migrate struct { 56 sourceName string 57 sourceDrv source.Driver 58 databaseName string 59 databaseDrv database.Driver 60 61 // Log accepts a Logger interface 62 Log Logger 63 64 // GracefulStop accepts `true` and will stop executing migrations 65 // as soon as possible at a safe break point, so that the database 66 // is not corrupted. 67 GracefulStop chan bool 68 isGracefulStop bool 69 70 isLockedMu *sync.Mutex 71 isLocked bool 72 73 // PrefetchMigrations defaults to DefaultPrefetchMigrations, 74 // but can be set per Migrate instance. 75 PrefetchMigrations uint 76 77 // LockTimeout defaults to DefaultLockTimeout, 78 // but can be set per Migrate instance. 79 LockTimeout time.Duration 80 } 81 82 // New returns a new Migrate instance from a source URL and a database URL. 83 // The URL scheme is defined by each driver. 84 func New(sourceUrl, databaseUrl string) (*Migrate, error) { 85 m := newCommon() 86 87 sourceName, err := sourceSchemeFromUrl(sourceUrl) 88 if err != nil { 89 return nil, err 90 } 91 m.sourceName = sourceName 92 93 databaseName, err := databaseSchemeFromUrl(databaseUrl) 94 if err != nil { 95 return nil, err 96 } 97 m.databaseName = databaseName 98 99 sourceDrv, err := source.Open(sourceUrl) 100 if err != nil { 101 return nil, err 102 } 103 m.sourceDrv = sourceDrv 104 105 databaseDrv, err := database.Open(databaseUrl) 106 if err != nil { 107 return nil, err 108 } 109 m.databaseDrv = databaseDrv 110 111 return m, nil 112 } 113 114 // NewWithDatabaseInstance returns a new Migrate instance from a source URL 115 // and an existing database instance. The source URL scheme is defined by each driver. 116 // Use any string that can serve as an identifier during logging as databaseName. 117 // You are responsible for closing the underlying database client if necessary. 118 func NewWithDatabaseInstance(sourceUrl string, databaseName string, databaseInstance database.Driver) (*Migrate, error) { 119 m := newCommon() 120 121 sourceName, err := schemeFromUrl(sourceUrl) 122 if err != nil { 123 return nil, err 124 } 125 m.sourceName = sourceName 126 127 m.databaseName = databaseName 128 129 sourceDrv, err := source.Open(sourceUrl) 130 if err != nil { 131 return nil, err 132 } 133 m.sourceDrv = sourceDrv 134 135 m.databaseDrv = databaseInstance 136 137 return m, nil 138 } 139 140 // NewWithSourceInstance returns a new Migrate instance from an existing source instance 141 // and a database URL. The database URL scheme is defined by each driver. 142 // Use any string that can serve as an identifier during logging as sourceName. 143 // You are responsible for closing the underlying source client if necessary. 144 func NewWithSourceInstance(sourceName string, sourceInstance source.Driver, databaseUrl string) (*Migrate, error) { 145 m := newCommon() 146 147 databaseName, err := schemeFromUrl(databaseUrl) 148 if err != nil { 149 return nil, err 150 } 151 m.databaseName = databaseName 152 153 m.sourceName = sourceName 154 155 databaseDrv, err := database.Open(databaseUrl) 156 if err != nil { 157 return nil, err 158 } 159 m.databaseDrv = databaseDrv 160 161 m.sourceDrv = sourceInstance 162 163 return m, nil 164 } 165 166 // NewWithInstance returns a new Migrate instance from an existing source and 167 // database instance. Use any string that can serve as an identifier during logging 168 // as sourceName and databaseName. You are responsible for closing down 169 // the underlying source and database client if necessary. 170 func NewWithInstance(sourceName string, sourceInstance source.Driver, databaseName string, databaseInstance database.Driver) (*Migrate, error) { 171 m := newCommon() 172 173 m.sourceName = sourceName 174 m.databaseName = databaseName 175 176 m.sourceDrv = sourceInstance 177 m.databaseDrv = databaseInstance 178 179 return m, nil 180 } 181 182 func newCommon() *Migrate { 183 return &Migrate{ 184 GracefulStop: make(chan bool, 1), 185 PrefetchMigrations: DefaultPrefetchMigrations, 186 LockTimeout: DefaultLockTimeout, 187 isLockedMu: &sync.Mutex{}, 188 } 189 } 190 191 // Close closes the source and the database. 192 func (m *Migrate) Close() (source error, database error) { 193 databaseSrvClose := make(chan error) 194 sourceSrvClose := make(chan error) 195 196 m.logVerbosePrintf("Closing source and database\n") 197 198 go func() { 199 databaseSrvClose <- m.databaseDrv.Close() 200 }() 201 202 go func() { 203 sourceSrvClose <- m.sourceDrv.Close() 204 }() 205 206 return <-sourceSrvClose, <-databaseSrvClose 207 } 208 209 // Migrate looks at the currently active migration version, 210 // then migrates either up or down to the specified version. 211 func (m *Migrate) Migrate(version uint) error { 212 if err := m.lock(); err != nil { 213 return err 214 } 215 216 curVersion, dirty, err := m.databaseDrv.Version() 217 if err != nil { 218 return m.unlockErr(err) 219 } 220 221 if dirty { 222 return m.unlockErr(ErrDirty{curVersion}) 223 } 224 225 ret := make(chan interface{}, m.PrefetchMigrations) 226 go m.read(curVersion, int(version), ret) 227 228 return m.unlockErr(m.runMigrations(ret)) 229 } 230 231 // Steps looks at the currently active migration version. 232 // It will migrate up if n > 0, and down if n < 0. 233 func (m *Migrate) Steps(n int) error { 234 if n == 0 { 235 return ErrNoChange 236 } 237 238 if err := m.lock(); err != nil { 239 return err 240 } 241 242 curVersion, dirty, err := m.databaseDrv.Version() 243 if err != nil { 244 return m.unlockErr(err) 245 } 246 247 if dirty { 248 return m.unlockErr(ErrDirty{curVersion}) 249 } 250 251 ret := make(chan interface{}, m.PrefetchMigrations) 252 253 if n > 0 { 254 go m.readUp(curVersion, n, ret) 255 } else { 256 go m.readDown(curVersion, -n, ret) 257 } 258 259 return m.unlockErr(m.runMigrations(ret)) 260 } 261 262 // Up looks at the currently active migration version 263 // and will migrate all the way up (applying all up migrations). 264 func (m *Migrate) Up() error { 265 if err := m.lock(); err != nil { 266 return err 267 } 268 269 curVersion, dirty, err := m.databaseDrv.Version() 270 if err != nil { 271 return m.unlockErr(err) 272 } 273 274 if dirty { 275 return m.unlockErr(ErrDirty{curVersion}) 276 } 277 278 ret := make(chan interface{}, m.PrefetchMigrations) 279 280 go m.readUp(curVersion, -1, ret) 281 return m.unlockErr(m.runMigrations(ret)) 282 } 283 284 // Down looks at the currently active migration version 285 // and will migrate all the way down (applying all down migrations). 286 func (m *Migrate) Down() error { 287 if err := m.lock(); err != nil { 288 return err 289 } 290 291 curVersion, dirty, err := m.databaseDrv.Version() 292 if err != nil { 293 return m.unlockErr(err) 294 } 295 296 if dirty { 297 return m.unlockErr(ErrDirty{curVersion}) 298 } 299 300 ret := make(chan interface{}, m.PrefetchMigrations) 301 go m.readDown(curVersion, -1, ret) 302 return m.unlockErr(m.runMigrations(ret)) 303 } 304 305 // Drop deletes everything in the database. 306 func (m *Migrate) Drop() error { 307 if err := m.lock(); err != nil { 308 return err 309 } 310 if err := m.databaseDrv.Drop(); err != nil { 311 return m.unlockErr(err) 312 } 313 return m.unlock() 314 } 315 316 // Run runs any migration provided by you against the database. 317 // It does not check any currently active version in database. 318 // Usually you don't need this function at all. Use Migrate, 319 // Steps, Up or Down instead. 320 func (m *Migrate) Run(migration ...*Migration) error { 321 if len(migration) == 0 { 322 return ErrNoChange 323 } 324 325 if err := m.lock(); err != nil { 326 return err 327 } 328 329 curVersion, dirty, err := m.databaseDrv.Version() 330 if err != nil { 331 return m.unlockErr(err) 332 } 333 334 if dirty { 335 return m.unlockErr(ErrDirty{curVersion}) 336 } 337 338 ret := make(chan interface{}, m.PrefetchMigrations) 339 340 go func() { 341 defer close(ret) 342 for _, migr := range migration { 343 if m.PrefetchMigrations > 0 && migr.Body != nil { 344 m.logVerbosePrintf("Start buffering %v\n", migr.LogString()) 345 } else { 346 m.logVerbosePrintf("Scheduled %v\n", migr.LogString()) 347 } 348 349 ret <- migr 350 go migr.Buffer() 351 } 352 }() 353 354 return m.unlockErr(m.runMigrations(ret)) 355 } 356 357 // Force sets a migration version. 358 // It does not check any currently active version in database. 359 // It resets the dirty state to false. 360 func (m *Migrate) Force(version int) error { 361 if version < -1 { 362 return ErrInvalidVersion 363 } 364 365 if err := m.lock(); err != nil { 366 return err 367 } 368 369 if err := m.databaseDrv.SetVersion(version, false); err != nil { 370 return m.unlockErr(err) 371 } 372 373 return m.unlock() 374 } 375 376 // Version returns the currently active migration version. 377 // If no migration has been applied, yet, it will return ErrNilVersion. 378 func (m *Migrate) Version() (version uint, dirty bool, err error) { 379 v, d, err := m.databaseDrv.Version() 380 if err != nil { 381 return 0, false, err 382 } 383 384 if v == database.NilVersion { 385 return 0, false, ErrNilVersion 386 } 387 388 return suint(v), d, nil 389 } 390 391 // read reads either up or down migrations from source `from` to `to`. 392 // Each migration is then written to the ret channel. 393 // If an error occurs during reading, that error is written to the ret channel, too. 394 // Once read is done reading it will close the ret channel. 395 func (m *Migrate) read(from int, to int, ret chan<- interface{}) { 396 defer close(ret) 397 398 // check if from version exists 399 if from >= 0 { 400 if err := m.versionExists(suint(from)); err != nil { 401 ret <- err 402 return 403 } 404 } 405 406 // check if to version exists 407 if to >= 0 { 408 if err := m.versionExists(suint(to)); err != nil { 409 ret <- err 410 return 411 } 412 } 413 414 // no change? 415 if from == to { 416 ret <- ErrNoChange 417 return 418 } 419 420 if from < to { 421 // it's going up 422 // apply first migration if from is nil version 423 if from == -1 { 424 firstVersion, err := m.sourceDrv.First() 425 if err != nil { 426 ret <- err 427 return 428 } 429 430 migr, err := m.newMigration(firstVersion, int(firstVersion)) 431 if err != nil { 432 ret <- err 433 return 434 } 435 436 ret <- migr 437 go migr.Buffer() 438 from = int(firstVersion) 439 } 440 441 // run until we reach target ... 442 for from < to { 443 if m.stop() { 444 return 445 } 446 447 next, err := m.sourceDrv.Next(suint(from)) 448 if err != nil { 449 ret <- err 450 return 451 } 452 453 migr, err := m.newMigration(next, int(next)) 454 if err != nil { 455 ret <- err 456 return 457 } 458 459 ret <- migr 460 go migr.Buffer() 461 from = int(next) 462 } 463 464 } else { 465 // it's going down 466 // run until we reach target ... 467 for from > to && from >= 0 { 468 if m.stop() { 469 return 470 } 471 472 prev, err := m.sourceDrv.Prev(suint(from)) 473 if os.IsNotExist(err) && to == -1 { 474 // apply nil migration 475 migr, err := m.newMigration(suint(from), -1) 476 if err != nil { 477 ret <- err 478 return 479 } 480 ret <- migr 481 go migr.Buffer() 482 return 483 484 } else if err != nil { 485 ret <- err 486 return 487 } 488 489 migr, err := m.newMigration(suint(from), int(prev)) 490 if err != nil { 491 ret <- err 492 return 493 } 494 495 ret <- migr 496 go migr.Buffer() 497 from = int(prev) 498 } 499 } 500 } 501 502 // readUp reads up migrations from `from` limitted by `limit`. 503 // limit can be -1, implying no limit and reading until there are no more migrations. 504 // Each migration is then written to the ret channel. 505 // If an error occurs during reading, that error is written to the ret channel, too. 506 // Once readUp is done reading it will close the ret channel. 507 func (m *Migrate) readUp(from int, limit int, ret chan<- interface{}) { 508 defer close(ret) 509 510 // check if from version exists 511 if from >= 0 { 512 if err := m.versionExists(suint(from)); err != nil { 513 ret <- err 514 return 515 } 516 } 517 518 if limit == 0 { 519 ret <- ErrNoChange 520 return 521 } 522 523 count := 0 524 for count < limit || limit == -1 { 525 if m.stop() { 526 return 527 } 528 529 // apply first migration if from is nil version 530 if from == -1 { 531 firstVersion, err := m.sourceDrv.First() 532 if err != nil { 533 ret <- err 534 return 535 } 536 537 migr, err := m.newMigration(firstVersion, int(firstVersion)) 538 if err != nil { 539 ret <- err 540 return 541 } 542 543 ret <- migr 544 go migr.Buffer() 545 from = int(firstVersion) 546 count++ 547 continue 548 } 549 550 // apply next migration 551 next, err := m.sourceDrv.Next(suint(from)) 552 if os.IsNotExist(err) { 553 // no limit, but no migrations applied? 554 if limit == -1 && count == 0 { 555 ret <- ErrNoChange 556 return 557 } 558 559 // no limit, reached end 560 if limit == -1 { 561 return 562 } 563 564 // reached end, and didn't apply any migrations 565 if limit > 0 && count == 0 { 566 ret <- os.ErrNotExist 567 return 568 } 569 570 // applied less migrations than limit? 571 if count < limit { 572 ret <- ErrShortLimit{suint(limit - count)} 573 return 574 } 575 } 576 if err != nil { 577 ret <- err 578 return 579 } 580 581 migr, err := m.newMigration(next, int(next)) 582 if err != nil { 583 ret <- err 584 return 585 } 586 587 ret <- migr 588 go migr.Buffer() 589 from = int(next) 590 count++ 591 } 592 } 593 594 // readDown reads down migrations from `from` limitted by `limit`. 595 // limit can be -1, implying no limit and reading until there are no more migrations. 596 // Each migration is then written to the ret channel. 597 // If an error occurs during reading, that error is written to the ret channel, too. 598 // Once readDown is done reading it will close the ret channel. 599 func (m *Migrate) readDown(from int, limit int, ret chan<- interface{}) { 600 defer close(ret) 601 602 // check if from version exists 603 if from >= 0 { 604 if err := m.versionExists(suint(from)); err != nil { 605 ret <- err 606 return 607 } 608 } 609 610 if limit == 0 { 611 ret <- ErrNoChange 612 return 613 } 614 615 // no change if already at nil version 616 if from == -1 && limit == -1 { 617 ret <- ErrNoChange 618 return 619 } 620 621 // can't go over limit if already at nil version 622 if from == -1 && limit > 0 { 623 ret <- os.ErrNotExist 624 return 625 } 626 627 count := 0 628 for count < limit || limit == -1 { 629 if m.stop() { 630 return 631 } 632 633 prev, err := m.sourceDrv.Prev(suint(from)) 634 if os.IsNotExist(err) { 635 // no limit or haven't reached limit, apply "first" migration 636 if limit == -1 || limit-count > 0 { 637 firstVersion, err := m.sourceDrv.First() 638 if err != nil { 639 ret <- err 640 return 641 } 642 643 migr, err := m.newMigration(firstVersion, -1) 644 if err != nil { 645 ret <- err 646 return 647 } 648 ret <- migr 649 go migr.Buffer() 650 count++ 651 } 652 653 if count < limit { 654 ret <- ErrShortLimit{suint(limit - count)} 655 } 656 return 657 } 658 if err != nil { 659 ret <- err 660 return 661 } 662 663 migr, err := m.newMigration(suint(from), int(prev)) 664 if err != nil { 665 ret <- err 666 return 667 } 668 669 ret <- migr 670 go migr.Buffer() 671 from = int(prev) 672 count++ 673 } 674 } 675 676 // runMigrations reads *Migration and error from a channel. Any other type 677 // sent on this channel will result in a panic. Each migration is then 678 // proxied to the database driver and run against the database. 679 // Before running a newly received migration it will check if it's supposed 680 // to stop execution because it might have received a stop signal on the 681 // GracefulStop channel. 682 func (m *Migrate) runMigrations(ret <-chan interface{}) error { 683 for r := range ret { 684 685 if m.stop() { 686 return nil 687 } 688 689 switch r.(type) { 690 case error: 691 return r.(error) 692 693 case *Migration: 694 migr := r.(*Migration) 695 696 // set version with dirty state 697 if err := m.databaseDrv.SetVersion(migr.TargetVersion, true); err != nil { 698 return err 699 } 700 701 if migr.Body != nil { 702 m.logVerbosePrintf("Read and execute %v\n", migr.LogString()) 703 if err := m.databaseDrv.Run(migr.BufferedBody); err != nil { 704 return err 705 } 706 } 707 708 // set clean state 709 if err := m.databaseDrv.SetVersion(migr.TargetVersion, false); err != nil { 710 return err 711 } 712 713 endTime := time.Now() 714 readTime := migr.FinishedReading.Sub(migr.StartedBuffering) 715 runTime := endTime.Sub(migr.FinishedReading) 716 717 // log either verbose or normal 718 if m.Log != nil { 719 if m.Log.Verbose() { 720 m.logPrintf("Finished %v (read %v, ran %v)\n", migr.LogString(), readTime, runTime) 721 } else { 722 m.logPrintf("%v (%v)\n", migr.LogString(), readTime+runTime) 723 } 724 } 725 726 default: 727 return fmt.Errorf("unknown type: %T with value: %+v", r, r) 728 } 729 } 730 return nil 731 } 732 733 // versionExists checks the source if either the up or down migration for 734 // the specified migration version exists. 735 func (m *Migrate) versionExists(version uint) error { 736 // try up migration first 737 up, _, err := m.sourceDrv.ReadUp(version) 738 if err == nil { 739 defer up.Close() 740 } 741 if os.IsExist(err) { 742 return nil 743 } else if !os.IsNotExist(err) { 744 return err 745 } 746 747 // then try down migration 748 down, _, err := m.sourceDrv.ReadDown(version) 749 if err == nil { 750 defer down.Close() 751 } 752 if os.IsExist(err) { 753 return nil 754 } else if !os.IsNotExist(err) { 755 return err 756 } 757 758 return os.ErrNotExist 759 } 760 761 // stop returns true if no more migrations should be run against the database 762 // because a stop signal was received on the GracefulStop channel. 763 // Calls are cheap and this function is not blocking. 764 func (m *Migrate) stop() bool { 765 if m.isGracefulStop { 766 return true 767 } 768 769 select { 770 case <-m.GracefulStop: 771 m.isGracefulStop = true 772 return true 773 774 default: 775 return false 776 } 777 } 778 779 // newMigration is a helper func that returns a *Migration for the 780 // specified version and targetVersion. 781 func (m *Migrate) newMigration(version uint, targetVersion int) (*Migration, error) { 782 var migr *Migration 783 784 if targetVersion >= int(version) { 785 r, identifier, err := m.sourceDrv.ReadUp(version) 786 if os.IsNotExist(err) { 787 // create "empty" migration 788 migr, err = NewMigration(nil, "", version, targetVersion) 789 if err != nil { 790 return nil, err 791 } 792 793 } else if err != nil { 794 return nil, err 795 796 } else { 797 // create migration from up source 798 migr, err = NewMigration(r, identifier, version, targetVersion) 799 if err != nil { 800 return nil, err 801 } 802 } 803 804 } else { 805 r, identifier, err := m.sourceDrv.ReadDown(version) 806 if os.IsNotExist(err) { 807 // create "empty" migration 808 migr, err = NewMigration(nil, "", version, targetVersion) 809 if err != nil { 810 return nil, err 811 } 812 813 } else if err != nil { 814 return nil, err 815 816 } else { 817 // create migration from down source 818 migr, err = NewMigration(r, identifier, version, targetVersion) 819 if err != nil { 820 return nil, err 821 } 822 } 823 } 824 825 if m.PrefetchMigrations > 0 && migr.Body != nil { 826 m.logVerbosePrintf("Start buffering %v\n", migr.LogString()) 827 } else { 828 m.logVerbosePrintf("Scheduled %v\n", migr.LogString()) 829 } 830 831 return migr, nil 832 } 833 834 // lock is a thread safe helper function to lock the database. 835 // It should be called as late as possible when running migrations. 836 func (m *Migrate) lock() error { 837 m.isLockedMu.Lock() 838 defer m.isLockedMu.Unlock() 839 840 if m.isLocked { 841 return ErrLocked 842 } 843 844 // create done channel, used in the timeout goroutine 845 done := make(chan bool, 1) 846 defer func() { 847 done <- true 848 }() 849 850 // use errchan to signal error back to this context 851 errchan := make(chan error, 2) 852 853 // start timeout goroutine 854 timeout := time.After(m.LockTimeout) 855 go func() { 856 for { 857 select { 858 case <-done: 859 return 860 case <-timeout: 861 errchan <- ErrLockTimeout 862 return 863 } 864 } 865 }() 866 867 // now try to acquire the lock 868 go func() { 869 if err := m.databaseDrv.Lock(); err != nil { 870 errchan <- err 871 } else { 872 errchan <- nil 873 } 874 return 875 }() 876 877 // wait until we either recieve ErrLockTimeout or error from Lock operation 878 err := <-errchan 879 if err == nil { 880 m.isLocked = true 881 } 882 return err 883 } 884 885 // unlock is a thread safe helper function to unlock the database. 886 // It should be called as early as possible when no more migrations are 887 // expected to be executed. 888 func (m *Migrate) unlock() error { 889 m.isLockedMu.Lock() 890 defer m.isLockedMu.Unlock() 891 892 if err := m.databaseDrv.Unlock(); err != nil { 893 // BUG: Can potentially create a deadlock. Add a timeout. 894 return err 895 } 896 897 m.isLocked = false 898 return nil 899 } 900 901 // unlockErr calls unlock and returns a combined error 902 // if a prevErr is not nil. 903 func (m *Migrate) unlockErr(prevErr error) error { 904 if err := m.unlock(); err != nil { 905 return NewMultiError(prevErr, err) 906 } 907 return prevErr 908 } 909 910 // logPrintf writes to m.Log if not nil 911 func (m *Migrate) logPrintf(format string, v ...interface{}) { 912 if m.Log != nil { 913 m.Log.Printf(format, v...) 914 } 915 } 916 917 // logVerbosePrintf writes to m.Log if not nil. Use for verbose logging output. 918 func (m *Migrate) logVerbosePrintf(format string, v ...interface{}) { 919 if m.Log != nil && m.Log.Verbose() { 920 m.Log.Printf(format, v...) 921 } 922 }